|
33 | 33 | package seccomp |
34 | 34 |
|
35 | 35 | import ( |
36 | | - "bufio" |
37 | | - "os" |
38 | | - "strings" |
| 36 | + "sync" |
39 | 37 |
|
40 | 38 | "golang.org/x/sys/unix" |
41 | 39 | ) |
42 | 40 |
|
43 | | -// isEnabled returns if the kernel has been configured to support seccomp. |
44 | | -// From https://github.com/opencontainers/runc/blob/v1.0.0-rc91/libcontainer/seccomp/seccomp_linux.go#L86-L102 |
45 | | -func isEnabled() bool { |
46 | | - // Try to read from /proc/self/status for kernels > 3.8 |
47 | | - s, err := parseStatusFile("/proc/self/status") |
48 | | - if err != nil { |
49 | | - // Check if Seccomp is supported, via CONFIG_SECCOMP. |
50 | | - if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL { |
51 | | - // Make sure the kernel has CONFIG_SECCOMP_FILTER. |
52 | | - if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL { |
53 | | - return true |
54 | | - } |
55 | | - } |
56 | | - return false |
57 | | - } |
58 | | - _, ok := s["Seccomp"] |
59 | | - return ok |
60 | | -} |
61 | | - |
62 | | -// parseStatusFile is from https://github.com/opencontainers/runc/blob/v1.0.0-rc91/libcontainer/seccomp/seccomp_linux.go#L243-L268 |
63 | | -func parseStatusFile(path string) (map[string]string, error) { |
64 | | - f, err := os.Open(path) |
65 | | - if err != nil { |
66 | | - return nil, err |
67 | | - } |
68 | | - defer f.Close() |
69 | | - |
70 | | - s := bufio.NewScanner(f) |
71 | | - status := make(map[string]string) |
72 | | - |
73 | | - for s.Scan() { |
74 | | - text := s.Text() |
75 | | - parts := strings.Split(text, ":") |
76 | | - |
77 | | - if len(parts) <= 1 { |
78 | | - continue |
79 | | - } |
80 | | - |
81 | | - status[parts[0]] = parts[1] |
82 | | - } |
83 | | - if err := s.Err(); err != nil { |
84 | | - return nil, err |
85 | | - } |
| 41 | +var ( |
| 42 | + enabled bool |
| 43 | + enabledOnce sync.Once |
| 44 | +) |
86 | 45 |
|
87 | | - return status, nil |
| 46 | +// isEnabled returns whether the kernel has been configured to support seccomp |
| 47 | +// (including the check for CONFIG_SECCOMP_FILTER kernel option). |
| 48 | +func isEnabled() bool { |
| 49 | + // Excerpts from prctl(2), section ERRORS: |
| 50 | + // |
| 51 | + // EACCES |
| 52 | + // option is PR_SET_SECCOMP and arg2 is SECCOMP_MODE_FILTER, but |
| 53 | + // the process does not have the CAP_SYS_ADMIN capability or has |
| 54 | + // not set the no_new_privs attribute <...>. |
| 55 | + // <...> |
| 56 | + // EFAULT |
| 57 | + // option is PR_SET_SECCOMP, arg2 is SECCOMP_MODE_FILTER, the |
| 58 | + // system was built with CONFIG_SECCOMP_FILTER, and arg3 is an |
| 59 | + // invalid address. |
| 60 | + // <...> |
| 61 | + // EINVAL |
| 62 | + // option is PR_SET_SECCOMP or PR_GET_SECCOMP, and the kernel |
| 63 | + // was not configured with CONFIG_SECCOMP. |
| 64 | + // |
| 65 | + // EINVAL |
| 66 | + // option is PR_SET_SECCOMP, arg2 is SECCOMP_MODE_FILTER, |
| 67 | + // and the kernel was not configured with CONFIG_SECCOMP_FILTER. |
| 68 | + // <end of quote> |
| 69 | + // |
| 70 | + // Meaning, in case these kernel options are set (this is what we check |
| 71 | + // for here), we will get some other error (most probably EACCES or |
| 72 | + // EFAULT). IOW, EINVAL means "seccomp not supported", any other error |
| 73 | + // means it is supported. |
| 74 | + |
| 75 | + enabledOnce.Do(func() { |
| 76 | + enabled = unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0) != unix.EINVAL |
| 77 | + }) |
| 78 | + |
| 79 | + return enabled |
88 | 80 | } |
0 commit comments