diff options
102 files changed, 3678 insertions, 1230 deletions
diff --git a/Documentation/prctl/seccomp_filter.txt b/Documentation/prctl/seccomp_filter.txt new file mode 100644 index 000000000000..597c3c581375 --- /dev/null +++ b/Documentation/prctl/seccomp_filter.txt | |||
@@ -0,0 +1,163 @@ | |||
1 | SECure COMPuting with filters | ||
2 | ============================= | ||
3 | |||
4 | Introduction | ||
5 | ------------ | ||
6 | |||
7 | A large number of system calls are exposed to every userland process | ||
8 | with many of them going unused for the entire lifetime of the process. | ||
9 | As system calls change and mature, bugs are found and eradicated. A | ||
10 | certain subset of userland applications benefit by having a reduced set | ||
11 | of available system calls. The resulting set reduces the total kernel | ||
12 | surface exposed to the application. System call filtering is meant for | ||
13 | use with those applications. | ||
14 | |||
15 | Seccomp filtering provides a means for a process to specify a filter for | ||
16 | incoming system calls. The filter is expressed as a Berkeley Packet | ||
17 | Filter (BPF) program, as with socket filters, except that the data | ||
18 | operated on is related to the system call being made: system call | ||
19 | number and the system call arguments. This allows for expressive | ||
20 | filtering of system calls using a filter program language with a long | ||
21 | history of being exposed to userland and a straightforward data set. | ||
22 | |||
23 | Additionally, BPF makes it impossible for users of seccomp to fall prey | ||
24 | to time-of-check-time-of-use (TOCTOU) attacks that are common in system | ||
25 | call interposition frameworks. BPF programs may not dereference | ||
26 | pointers which constrains all filters to solely evaluating the system | ||
27 | call arguments directly. | ||
28 | |||
29 | What it isn't | ||
30 | ------------- | ||
31 | |||
32 | System call filtering isn't a sandbox. It provides a clearly defined | ||
33 | mechanism for minimizing the exposed kernel surface. It is meant to be | ||
34 | a tool for sandbox developers to use. Beyond that, policy for logical | ||
35 | behavior and information flow should be managed with a combination of | ||
36 | other system hardening techniques and, potentially, an LSM of your | ||
37 | choosing. Expressive, dynamic filters provide further options down this | ||
38 | path (avoiding pathological sizes or selecting which of the multiplexed | ||
39 | system calls in socketcall() is allowed, for instance) which could be | ||
40 | construed, incorrectly, as a more complete sandboxing solution. | ||
41 | |||
42 | Usage | ||
43 | ----- | ||
44 | |||
45 | An additional seccomp mode is added and is enabled using the same | ||
46 | prctl(2) call as the strict seccomp. If the architecture has | ||
47 | CONFIG_HAVE_ARCH_SECCOMP_FILTER, then filters may be added as below: | ||
48 | |||
49 | PR_SET_SECCOMP: | ||
50 | Now takes an additional argument which specifies a new filter | ||
51 | using a BPF program. | ||
52 | The BPF program will be executed over struct seccomp_data | ||
53 | reflecting the system call number, arguments, and other | ||
54 | metadata. The BPF program must then return one of the | ||
55 | acceptable values to inform the kernel which action should be | ||
56 | taken. | ||
57 | |||
58 | Usage: | ||
59 | prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog); | ||
60 | |||
61 | The 'prog' argument is a pointer to a struct sock_fprog which | ||
62 | will contain the filter program. If the program is invalid, the | ||
63 | call will return -1 and set errno to EINVAL. | ||
64 | |||
65 | If fork/clone and execve are allowed by @prog, any child | ||
66 | processes will be constrained to the same filters and system | ||
67 | call ABI as the parent. | ||
68 | |||
69 | Prior to use, the task must call prctl(PR_SET_NO_NEW_PRIVS, 1) or | ||
70 | run with CAP_SYS_ADMIN privileges in its namespace. If these are not | ||
71 | true, -EACCES will be returned. This requirement ensures that filter | ||
72 | programs cannot be applied to child processes with greater privileges | ||
73 | than the task that installed them. | ||
74 | |||
75 | Additionally, if prctl(2) is allowed by the attached filter, | ||
76 | additional filters may be layered on which will increase evaluation | ||
77 | time, but allow for further decreasing the attack surface during | ||
78 | execution of a process. | ||
79 | |||
80 | The above call returns 0 on success and non-zero on error. | ||
81 | |||
82 | Return values | ||
83 | ------------- | ||
84 | A seccomp filter may return any of the following values. If multiple | ||
85 | filters exist, the return value for the evaluation of a given system | ||
86 | call will always use the highest precedent value. (For example, | ||
87 | SECCOMP_RET_KILL will always take precedence.) | ||
88 | |||
89 | In precedence order, they are: | ||
90 | |||
91 | SECCOMP_RET_KILL: | ||
92 | Results in the task exiting immediately without executing the | ||
93 | system call. The exit status of the task (status & 0x7f) will | ||
94 | be SIGSYS, not SIGKILL. | ||
95 | |||
96 | SECCOMP_RET_TRAP: | ||
97 | Results in the kernel sending a SIGSYS signal to the triggering | ||
98 | task without executing the system call. The kernel will | ||
99 | rollback the register state to just before the system call | ||
100 | entry such that a signal handler in the task will be able to | ||
101 | inspect the ucontext_t->uc_mcontext registers and emulate | ||
102 | system call success or failure upon return from the signal | ||
103 | handler. | ||
104 | |||
105 | The SECCOMP_RET_DATA portion of the return value will be passed | ||
106 | as si_errno. | ||
107 | |||
108 | SIGSYS triggered by seccomp will have a si_code of SYS_SECCOMP. | ||
109 | |||
110 | SECCOMP_RET_ERRNO: | ||
111 | Results in the lower 16-bits of the return value being passed | ||
112 | to userland as the errno without executing the system call. | ||
113 | |||
114 | SECCOMP_RET_TRACE: | ||
115 | When returned, this value will cause the kernel to attempt to | ||
116 | notify a ptrace()-based tracer prior to executing the system | ||
117 | call. If there is no tracer present, -ENOSYS is returned to | ||
118 | userland and the system call is not executed. | ||
119 | |||
120 | A tracer will be notified if it requests PTRACE_O_TRACESECCOMP | ||
121 | using ptrace(PTRACE_SETOPTIONS). The tracer will be notified | ||
122 | of a PTRACE_EVENT_SECCOMP and the SECCOMP_RET_DATA portion of | ||
123 | the BPF program return value will be available to the tracer | ||
124 | via PTRACE_GETEVENTMSG. | ||
125 | |||
126 | SECCOMP_RET_ALLOW: | ||
127 | Results in the system call being executed. | ||
128 | |||
129 | If multiple filters exist, the return value for the evaluation of a | ||
130 | given system call will always use the highest precedent value. | ||
131 | |||
132 | Precedence is only determined using the SECCOMP_RET_ACTION mask. When | ||
133 | multiple filters return values of the same precedence, only the | ||
134 | SECCOMP_RET_DATA from the most recently installed filter will be | ||
135 | returned. | ||
136 | |||
137 | Pitfalls | ||
138 | -------- | ||
139 | |||
140 | The biggest pitfall to avoid during use is filtering on system call | ||
141 | number without checking the architecture value. Why? On any | ||
142 | architecture that supports multiple system call invocation conventions, | ||
143 | the system call numbers may vary based on the specific invocation. If | ||
144 | the numbers in the different calling conventions overlap, then checks in | ||
145 | the filters may be abused. Always check the arch value! | ||
146 | |||
147 | Example | ||
148 | ------- | ||
149 | |||
150 | The samples/seccomp/ directory contains both an x86-specific example | ||
151 | and a more generic example of a higher level macro interface for BPF | ||
152 | program generation. | ||
153 | |||
154 | |||
155 | |||
156 | Adding architecture support | ||
157 | ----------------------- | ||
158 | |||
159 | See arch/Kconfig for the authoritative requirements. In general, if an | ||
160 | architecture supports both ptrace_event and seccomp, it will be able to | ||
161 | support seccomp filter with minor fixup: SIGSYS support and seccomp return | ||
162 | value checking. Then it must just add CONFIG_HAVE_ARCH_SECCOMP_FILTER | ||
163 | to its arch-specific Kconfig. | ||
diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt index d2f72ae66432..a416479b8a1c 100644 --- a/Documentation/security/Smack.txt +++ b/Documentation/security/Smack.txt | |||
@@ -15,7 +15,7 @@ at hand. | |||
15 | 15 | ||
16 | Smack consists of three major components: | 16 | Smack consists of three major components: |
17 | - The kernel | 17 | - The kernel |
18 | - A start-up script and a few modified applications | 18 | - Basic utilities, which are helpful but not required |
19 | - Configuration data | 19 | - Configuration data |
20 | 20 | ||
21 | The kernel component of Smack is implemented as a Linux | 21 | The kernel component of Smack is implemented as a Linux |
@@ -23,37 +23,28 @@ Security Modules (LSM) module. It requires netlabel and | |||
23 | works best with file systems that support extended attributes, | 23 | works best with file systems that support extended attributes, |
24 | although xattr support is not strictly required. | 24 | although xattr support is not strictly required. |
25 | It is safe to run a Smack kernel under a "vanilla" distribution. | 25 | It is safe to run a Smack kernel under a "vanilla" distribution. |
26 | |||
26 | Smack kernels use the CIPSO IP option. Some network | 27 | Smack kernels use the CIPSO IP option. Some network |
27 | configurations are intolerant of IP options and can impede | 28 | configurations are intolerant of IP options and can impede |
28 | access to systems that use them as Smack does. | 29 | access to systems that use them as Smack does. |
29 | 30 | ||
30 | The startup script etc-init.d-smack should be installed | 31 | The current git repositories for Smack user space are: |
31 | in /etc/init.d/smack and should be invoked early in the | ||
32 | start-up process. On Fedora rc5.d/S02smack is recommended. | ||
33 | This script ensures that certain devices have the correct | ||
34 | Smack attributes and loads the Smack configuration if | ||
35 | any is defined. This script invokes two programs that | ||
36 | ensure configuration data is properly formatted. These | ||
37 | programs are /usr/sbin/smackload and /usr/sin/smackcipso. | ||
38 | The system will run just fine without these programs, | ||
39 | but it will be difficult to set access rules properly. | ||
40 | |||
41 | A version of "ls" that provides a "-M" option to display | ||
42 | Smack labels on long listing is available. | ||
43 | 32 | ||
44 | A hacked version of sshd that allows network logins by users | 33 | git@gitorious.org:meego-platform-security/smackutil.git |
45 | with specific Smack labels is available. This version does | 34 | git@gitorious.org:meego-platform-security/libsmack.git |
46 | not work for scp. You must set the /etc/ssh/sshd_config | ||
47 | line: | ||
48 | UsePrivilegeSeparation no | ||
49 | 35 | ||
50 | The format of /etc/smack/usr is: | 36 | These should make and install on most modern distributions. |
37 | There are three commands included in smackutil: | ||
51 | 38 | ||
52 | username smack | 39 | smackload - properly formats data for writing to /smack/load |
40 | smackcipso - properly formats data for writing to /smack/cipso | ||
41 | chsmack - display or set Smack extended attribute values | ||
53 | 42 | ||
54 | In keeping with the intent of Smack, configuration data is | 43 | In keeping with the intent of Smack, configuration data is |
55 | minimal and not strictly required. The most important | 44 | minimal and not strictly required. The most important |
56 | configuration step is mounting the smackfs pseudo filesystem. | 45 | configuration step is mounting the smackfs pseudo filesystem. |
46 | If smackutil is installed the startup script will take care | ||
47 | of this, but it can be manually as well. | ||
57 | 48 | ||
58 | Add this line to /etc/fstab: | 49 | Add this line to /etc/fstab: |
59 | 50 | ||
@@ -61,19 +52,148 @@ Add this line to /etc/fstab: | |||
61 | 52 | ||
62 | and create the /smack directory for mounting. | 53 | and create the /smack directory for mounting. |
63 | 54 | ||
64 | Smack uses extended attributes (xattrs) to store file labels. | 55 | Smack uses extended attributes (xattrs) to store labels on filesystem |
65 | The command to set a Smack label on a file is: | 56 | objects. The attributes are stored in the extended attribute security |
57 | name space. A process must have CAP_MAC_ADMIN to change any of these | ||
58 | attributes. | ||
59 | |||
60 | The extended attributes that Smack uses are: | ||
61 | |||
62 | SMACK64 | ||
63 | Used to make access control decisions. In almost all cases | ||
64 | the label given to a new filesystem object will be the label | ||
65 | of the process that created it. | ||
66 | SMACK64EXEC | ||
67 | The Smack label of a process that execs a program file with | ||
68 | this attribute set will run with this attribute's value. | ||
69 | SMACK64MMAP | ||
70 | Don't allow the file to be mmapped by a process whose Smack | ||
71 | label does not allow all of the access permitted to a process | ||
72 | with the label contained in this attribute. This is a very | ||
73 | specific use case for shared libraries. | ||
74 | SMACK64TRANSMUTE | ||
75 | Can only have the value "TRUE". If this attribute is present | ||
76 | on a directory when an object is created in the directory and | ||
77 | the Smack rule (more below) that permitted the write access | ||
78 | to the directory includes the transmute ("t") mode the object | ||
79 | gets the label of the directory instead of the label of the | ||
80 | creating process. If the object being created is a directory | ||
81 | the SMACK64TRANSMUTE attribute is set as well. | ||
82 | SMACK64IPIN | ||
83 | This attribute is only available on file descriptors for sockets. | ||
84 | Use the Smack label in this attribute for access control | ||
85 | decisions on packets being delivered to this socket. | ||
86 | SMACK64IPOUT | ||
87 | This attribute is only available on file descriptors for sockets. | ||
88 | Use the Smack label in this attribute for access control | ||
89 | decisions on packets coming from this socket. | ||
90 | |||
91 | There are multiple ways to set a Smack label on a file: | ||
66 | 92 | ||
67 | # attr -S -s SMACK64 -V "value" path | 93 | # attr -S -s SMACK64 -V "value" path |
94 | # chsmack -a value path | ||
68 | 95 | ||
69 | NOTE: Smack labels are limited to 23 characters. The attr command | 96 | A process can see the smack label it is running with by |
70 | does not enforce this restriction and can be used to set | 97 | reading /proc/self/attr/current. A process with CAP_MAC_ADMIN |
71 | invalid Smack labels on files. | 98 | can set the process smack by writing there. |
72 | 99 | ||
73 | If you don't do anything special all users will get the floor ("_") | 100 | Most Smack configuration is accomplished by writing to files |
74 | label when they log in. If you do want to log in via the hacked ssh | 101 | in the smackfs filesystem. This pseudo-filesystem is usually |
75 | at other labels use the attr command to set the smack value on the | 102 | mounted on /smack. |
76 | home directory and its contents. | 103 | |
104 | access | ||
105 | This interface reports whether a subject with the specified | ||
106 | Smack label has a particular access to an object with a | ||
107 | specified Smack label. Write a fixed format access rule to | ||
108 | this file. The next read will indicate whether the access | ||
109 | would be permitted. The text will be either "1" indicating | ||
110 | access, or "0" indicating denial. | ||
111 | access2 | ||
112 | This interface reports whether a subject with the specified | ||
113 | Smack label has a particular access to an object with a | ||
114 | specified Smack label. Write a long format access rule to | ||
115 | this file. The next read will indicate whether the access | ||
116 | would be permitted. The text will be either "1" indicating | ||
117 | access, or "0" indicating denial. | ||
118 | ambient | ||
119 | This contains the Smack label applied to unlabeled network | ||
120 | packets. | ||
121 | cipso | ||
122 | This interface allows a specific CIPSO header to be assigned | ||
123 | to a Smack label. The format accepted on write is: | ||
124 | "%24s%4d%4d"["%4d"]... | ||
125 | The first string is a fixed Smack label. The first number is | ||
126 | the level to use. The second number is the number of categories. | ||
127 | The following numbers are the categories. | ||
128 | "level-3-cats-5-19 3 2 5 19" | ||
129 | cipso2 | ||
130 | This interface allows a specific CIPSO header to be assigned | ||
131 | to a Smack label. The format accepted on write is: | ||
132 | "%s%4d%4d"["%4d"]... | ||
133 | The first string is a long Smack label. The first number is | ||
134 | the level to use. The second number is the number of categories. | ||
135 | The following numbers are the categories. | ||
136 | "level-3-cats-5-19 3 2 5 19" | ||
137 | direct | ||
138 | This contains the CIPSO level used for Smack direct label | ||
139 | representation in network packets. | ||
140 | doi | ||
141 | This contains the CIPSO domain of interpretation used in | ||
142 | network packets. | ||
143 | load | ||
144 | This interface allows access control rules in addition to | ||
145 | the system defined rules to be specified. The format accepted | ||
146 | on write is: | ||
147 | "%24s%24s%5s" | ||
148 | where the first string is the subject label, the second the | ||
149 | object label, and the third the requested access. The access | ||
150 | string may contain only the characters "rwxat-", and specifies | ||
151 | which sort of access is allowed. The "-" is a placeholder for | ||
152 | permissions that are not allowed. The string "r-x--" would | ||
153 | specify read and execute access. Labels are limited to 23 | ||
154 | characters in length. | ||
155 | load2 | ||
156 | This interface allows access control rules in addition to | ||
157 | the system defined rules to be specified. The format accepted | ||
158 | on write is: | ||
159 | "%s %s %s" | ||
160 | where the first string is the subject label, the second the | ||
161 | object label, and the third the requested access. The access | ||
162 | string may contain only the characters "rwxat-", and specifies | ||
163 | which sort of access is allowed. The "-" is a placeholder for | ||
164 | permissions that are not allowed. The string "r-x--" would | ||
165 | specify read and execute access. | ||
166 | load-self | ||
167 | This interface allows process specific access rules to be | ||
168 | defined. These rules are only consulted if access would | ||
169 | otherwise be permitted, and are intended to provide additional | ||
170 | restrictions on the process. The format is the same as for | ||
171 | the load interface. | ||
172 | load-self2 | ||
173 | This interface allows process specific access rules to be | ||
174 | defined. These rules are only consulted if access would | ||
175 | otherwise be permitted, and are intended to provide additional | ||
176 | restrictions on the process. The format is the same as for | ||
177 | the load2 interface. | ||
178 | logging | ||
179 | This contains the Smack logging state. | ||
180 | mapped | ||
181 | This contains the CIPSO level used for Smack mapped label | ||
182 | representation in network packets. | ||
183 | netlabel | ||
184 | This interface allows specific internet addresses to be | ||
185 | treated as single label hosts. Packets are sent to single | ||
186 | label hosts without CIPSO headers, but only from processes | ||
187 | that have Smack write access to the host label. All packets | ||
188 | received from single label hosts are given the specified | ||
189 | label. The format accepted on write is: | ||
190 | "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label". | ||
191 | onlycap | ||
192 | This contains the label processes must have for CAP_MAC_ADMIN | ||
193 | and CAP_MAC_OVERRIDE to be effective. If this file is empty | ||
194 | these capabilities are effective at for processes with any | ||
195 | label. The value is set by writing the desired label to the | ||
196 | file or cleared by writing "-" to the file. | ||
77 | 197 | ||
78 | You can add access rules in /etc/smack/accesses. They take the form: | 198 | You can add access rules in /etc/smack/accesses. They take the form: |
79 | 199 | ||
@@ -83,10 +203,6 @@ access is a combination of the letters rwxa which specify the | |||
83 | kind of access permitted a subject with subjectlabel on an | 203 | kind of access permitted a subject with subjectlabel on an |
84 | object with objectlabel. If there is no rule no access is allowed. | 204 | object with objectlabel. If there is no rule no access is allowed. |
85 | 205 | ||
86 | A process can see the smack label it is running with by | ||
87 | reading /proc/self/attr/current. A privileged process can | ||
88 | set the process smack by writing there. | ||
89 | |||
90 | Look for additional programs on http://schaufler-ca.com | 206 | Look for additional programs on http://schaufler-ca.com |
91 | 207 | ||
92 | From the Smack Whitepaper: | 208 | From the Smack Whitepaper: |
@@ -186,7 +302,7 @@ team. Smack labels are unstructured, case sensitive, and the only operation | |||
186 | ever performed on them is comparison for equality. Smack labels cannot | 302 | ever performed on them is comparison for equality. Smack labels cannot |
187 | contain unprintable characters, the "/" (slash), the "\" (backslash), the "'" | 303 | contain unprintable characters, the "/" (slash), the "\" (backslash), the "'" |
188 | (quote) and '"' (double-quote) characters. | 304 | (quote) and '"' (double-quote) characters. |
189 | Smack labels cannot begin with a '-', which is reserved for special options. | 305 | Smack labels cannot begin with a '-'. This is reserved for special options. |
190 | 306 | ||
191 | There are some predefined labels: | 307 | There are some predefined labels: |
192 | 308 | ||
@@ -194,7 +310,7 @@ There are some predefined labels: | |||
194 | ^ Pronounced "hat", a single circumflex character. | 310 | ^ Pronounced "hat", a single circumflex character. |
195 | * Pronounced "star", a single asterisk character. | 311 | * Pronounced "star", a single asterisk character. |
196 | ? Pronounced "huh", a single question mark character. | 312 | ? Pronounced "huh", a single question mark character. |
197 | @ Pronounced "Internet", a single at sign character. | 313 | @ Pronounced "web", a single at sign character. |
198 | 314 | ||
199 | Every task on a Smack system is assigned a label. System tasks, such as | 315 | Every task on a Smack system is assigned a label. System tasks, such as |
200 | init(8) and systems daemons, are run with the floor ("_") label. User tasks | 316 | init(8) and systems daemons, are run with the floor ("_") label. User tasks |
@@ -246,13 +362,14 @@ The format of an access rule is: | |||
246 | 362 | ||
247 | Where subject-label is the Smack label of the task, object-label is the Smack | 363 | Where subject-label is the Smack label of the task, object-label is the Smack |
248 | label of the thing being accessed, and access is a string specifying the sort | 364 | label of the thing being accessed, and access is a string specifying the sort |
249 | of access allowed. The Smack labels are limited to 23 characters. The access | 365 | of access allowed. The access specification is searched for letters that |
250 | specification is searched for letters that describe access modes: | 366 | describe access modes: |
251 | 367 | ||
252 | a: indicates that append access should be granted. | 368 | a: indicates that append access should be granted. |
253 | r: indicates that read access should be granted. | 369 | r: indicates that read access should be granted. |
254 | w: indicates that write access should be granted. | 370 | w: indicates that write access should be granted. |
255 | x: indicates that execute access should be granted. | 371 | x: indicates that execute access should be granted. |
372 | t: indicates that the rule requests transmutation. | ||
256 | 373 | ||
257 | Uppercase values for the specification letters are allowed as well. | 374 | Uppercase values for the specification letters are allowed as well. |
258 | Access mode specifications can be in any order. Examples of acceptable rules | 375 | Access mode specifications can be in any order. Examples of acceptable rules |
@@ -273,7 +390,7 @@ Examples of unacceptable rules are: | |||
273 | 390 | ||
274 | Spaces are not allowed in labels. Since a subject always has access to files | 391 | Spaces are not allowed in labels. Since a subject always has access to files |
275 | with the same label specifying a rule for that case is pointless. Only | 392 | with the same label specifying a rule for that case is pointless. Only |
276 | valid letters (rwxaRWXA) and the dash ('-') character are allowed in | 393 | valid letters (rwxatRWXAT) and the dash ('-') character are allowed in |
277 | access specifications. The dash is a placeholder, so "a-r" is the same | 394 | access specifications. The dash is a placeholder, so "a-r" is the same |
278 | as "ar". A lone dash is used to specify that no access should be allowed. | 395 | as "ar". A lone dash is used to specify that no access should be allowed. |
279 | 396 | ||
@@ -297,6 +414,13 @@ but not any of its attributes by the circumstance of having read access to the | |||
297 | containing directory but not to the differently labeled file. This is an | 414 | containing directory but not to the differently labeled file. This is an |
298 | artifact of the file name being data in the directory, not a part of the file. | 415 | artifact of the file name being data in the directory, not a part of the file. |
299 | 416 | ||
417 | If a directory is marked as transmuting (SMACK64TRANSMUTE=TRUE) and the | ||
418 | access rule that allows a process to create an object in that directory | ||
419 | includes 't' access the label assigned to the new object will be that | ||
420 | of the directory, not the creating process. This makes it much easier | ||
421 | for two processes with different labels to share data without granting | ||
422 | access to all of their files. | ||
423 | |||
300 | IPC objects, message queues, semaphore sets, and memory segments exist in flat | 424 | IPC objects, message queues, semaphore sets, and memory segments exist in flat |
301 | namespaces and access requests are only required to match the object in | 425 | namespaces and access requests are only required to match the object in |
302 | question. | 426 | question. |
diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt index a9511f179069..e369de2d48cd 100644 --- a/Documentation/security/Yama.txt +++ b/Documentation/security/Yama.txt | |||
@@ -34,7 +34,7 @@ parent to a child process (i.e. direct "gdb EXE" and "strace EXE" still | |||
34 | work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID" | 34 | work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID" |
35 | still work as root). | 35 | still work as root). |
36 | 36 | ||
37 | For software that has defined application-specific relationships | 37 | In mode 1, software that has defined application-specific relationships |
38 | between a debugging process and its inferior (crash handlers, etc), | 38 | between a debugging process and its inferior (crash handlers, etc), |
39 | prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which | 39 | prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which |
40 | other process (and its descendents) are allowed to call PTRACE_ATTACH | 40 | other process (and its descendents) are allowed to call PTRACE_ATTACH |
@@ -46,6 +46,8 @@ restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...) | |||
46 | so that any otherwise allowed process (even those in external pid namespaces) | 46 | so that any otherwise allowed process (even those in external pid namespaces) |
47 | may attach. | 47 | may attach. |
48 | 48 | ||
49 | These restrictions do not change how ptrace via PTRACE_TRACEME operates. | ||
50 | |||
49 | The sysctl settings are: | 51 | The sysctl settings are: |
50 | 52 | ||
51 | 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other | 53 | 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other |
@@ -60,6 +62,12 @@ The sysctl settings are: | |||
60 | inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare | 62 | inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare |
61 | an allowed debugger PID to call PTRACE_ATTACH on the inferior. | 63 | an allowed debugger PID to call PTRACE_ATTACH on the inferior. |
62 | 64 | ||
65 | 2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace | ||
66 | with PTRACE_ATTACH. | ||
67 | |||
68 | 3 - no attach: no processes may use ptrace with PTRACE_ATTACH. Once set, | ||
69 | this sysctl cannot be changed to a lower value. | ||
70 | |||
63 | The original children-only logic was based on the restrictions in grsecurity. | 71 | The original children-only logic was based on the restrictions in grsecurity. |
64 | 72 | ||
65 | ============================================================== | 73 | ============================================================== |
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index d389acd31e19..aa0dbd74b71b 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt | |||
@@ -805,6 +805,23 @@ The keyctl syscall functions are: | |||
805 | kernel and resumes executing userspace. | 805 | kernel and resumes executing userspace. |
806 | 806 | ||
807 | 807 | ||
808 | (*) Invalidate a key. | ||
809 | |||
810 | long keyctl(KEYCTL_INVALIDATE, key_serial_t key); | ||
811 | |||
812 | This function marks a key as being invalidated and then wakes up the | ||
813 | garbage collector. The garbage collector immediately removes invalidated | ||
814 | keys from all keyrings and deletes the key when its reference count | ||
815 | reaches zero. | ||
816 | |||
817 | Keys that are marked invalidated become invisible to normal key operations | ||
818 | immediately, though they are still visible in /proc/keys until deleted | ||
819 | (they're marked with an 'i' flag). | ||
820 | |||
821 | A process must have search permission on the key for this function to be | ||
822 | successful. | ||
823 | |||
824 | |||
808 | =============== | 825 | =============== |
809 | KERNEL SERVICES | 826 | KERNEL SERVICES |
810 | =============== | 827 | =============== |
diff --git a/MAINTAINERS b/MAINTAINERS index 5ccca1ca0077..d4abe7572ead 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1733,6 +1733,7 @@ S: Supported | |||
1733 | F: include/linux/capability.h | 1733 | F: include/linux/capability.h |
1734 | F: security/capability.c | 1734 | F: security/capability.c |
1735 | F: security/commoncap.c | 1735 | F: security/commoncap.c |
1736 | F: kernel/capability.c | ||
1736 | 1737 | ||
1737 | CELL BROADBAND ENGINE ARCHITECTURE | 1738 | CELL BROADBAND ENGINE ARCHITECTURE |
1738 | M: Arnd Bergmann <arnd@arndb.de> | 1739 | M: Arnd Bergmann <arnd@arndb.de> |
@@ -5950,7 +5951,7 @@ SECURITY SUBSYSTEM | |||
5950 | M: James Morris <james.l.morris@oracle.com> | 5951 | M: James Morris <james.l.morris@oracle.com> |
5951 | L: linux-security-module@vger.kernel.org (suggested Cc:) | 5952 | L: linux-security-module@vger.kernel.org (suggested Cc:) |
5952 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git | 5953 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git |
5953 | W: http://security.wiki.kernel.org/ | 5954 | W: http://kernsec.org/ |
5954 | S: Supported | 5955 | S: Supported |
5955 | F: security/ | 5956 | F: security/ |
5956 | 5957 | ||
diff --git a/arch/Kconfig b/arch/Kconfig index bd265a217bd2..1f9461b9cc89 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -231,4 +231,27 @@ config HAVE_CMPXCHG_DOUBLE | |||
231 | config ARCH_WANT_OLD_COMPAT_IPC | 231 | config ARCH_WANT_OLD_COMPAT_IPC |
232 | bool | 232 | bool |
233 | 233 | ||
234 | config HAVE_ARCH_SECCOMP_FILTER | ||
235 | bool | ||
236 | help | ||
237 | An arch should select this symbol if it provides all of these things: | ||
238 | - syscall_get_arch() | ||
239 | - syscall_get_arguments() | ||
240 | - syscall_rollback() | ||
241 | - syscall_set_return_value() | ||
242 | - SIGSYS siginfo_t support | ||
243 | - secure_computing is called from a ptrace_event()-safe context | ||
244 | - secure_computing return value is checked and a return value of -1 | ||
245 | results in the system call being skipped immediately. | ||
246 | |||
247 | config SECCOMP_FILTER | ||
248 | def_bool y | ||
249 | depends on HAVE_ARCH_SECCOMP_FILTER && SECCOMP && NET | ||
250 | help | ||
251 | Enable tasks to build secure computing environments defined | ||
252 | in terms of Berkeley Packet Filter programs which implement | ||
253 | task-defined system call filtering polices. | ||
254 | |||
255 | See Documentation/prctl/seccomp_filter.txt for details. | ||
256 | |||
234 | source "kernel/gcov/Kconfig" | 257 | source "kernel/gcov/Kconfig" |
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index 6eb2aa927d89..ab1b9db661f3 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c | |||
@@ -136,7 +136,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
136 | { | 136 | { |
137 | long ret = 0; | 137 | long ret = 0; |
138 | 138 | ||
139 | secure_computing(regs->r12); | 139 | secure_computing_strict(regs->r12); |
140 | 140 | ||
141 | if (test_thread_flag(TIF_SYSCALL_TRACE) && | 141 | if (test_thread_flag(TIF_SYSCALL_TRACE) && |
142 | tracehook_report_syscall_entry(regs)) | 142 | tracehook_report_syscall_entry(regs)) |
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 7c24c2973c6d..4812c6d916e4 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c | |||
@@ -535,7 +535,7 @@ static inline int audit_arch(void) | |||
535 | asmlinkage void syscall_trace_enter(struct pt_regs *regs) | 535 | asmlinkage void syscall_trace_enter(struct pt_regs *regs) |
536 | { | 536 | { |
537 | /* do the secure computing check first */ | 537 | /* do the secure computing check first */ |
538 | secure_computing(regs->regs[2]); | 538 | secure_computing_strict(regs->regs[2]); |
539 | 539 | ||
540 | if (!(current->ptrace & PT_PTRACED)) | 540 | if (!(current->ptrace & PT_PTRACED)) |
541 | goto out; | 541 | goto out; |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 8d8e028893be..dd5e214cdf21 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -1710,7 +1710,7 @@ long do_syscall_trace_enter(struct pt_regs *regs) | |||
1710 | { | 1710 | { |
1711 | long ret = 0; | 1711 | long ret = 0; |
1712 | 1712 | ||
1713 | secure_computing(regs->gpr[0]); | 1713 | secure_computing_strict(regs->gpr[0]); |
1714 | 1714 | ||
1715 | if (test_thread_flag(TIF_SYSCALL_TRACE) && | 1715 | if (test_thread_flag(TIF_SYSCALL_TRACE) && |
1716 | tracehook_report_syscall_entry(regs)) | 1716 | tracehook_report_syscall_entry(regs)) |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 02f300fbf070..4993e689b2c2 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -719,7 +719,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
719 | long ret = 0; | 719 | long ret = 0; |
720 | 720 | ||
721 | /* Do the secure computing check first. */ | 721 | /* Do the secure computing check first. */ |
722 | secure_computing(regs->gprs[2]); | 722 | secure_computing_strict(regs->gprs[2]); |
723 | 723 | ||
724 | /* | 724 | /* |
725 | * The sysc_tracesys code in entry.S stored the system | 725 | * The sysc_tracesys code in entry.S stored the system |
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 9698671444e6..81f999a672f6 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c | |||
@@ -503,7 +503,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
503 | { | 503 | { |
504 | long ret = 0; | 504 | long ret = 0; |
505 | 505 | ||
506 | secure_computing(regs->regs[0]); | 506 | secure_computing_strict(regs->regs[0]); |
507 | 507 | ||
508 | if (test_thread_flag(TIF_SYSCALL_TRACE) && | 508 | if (test_thread_flag(TIF_SYSCALL_TRACE) && |
509 | tracehook_report_syscall_entry(regs)) | 509 | tracehook_report_syscall_entry(regs)) |
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index bc81e07dc098..af90339dadcd 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c | |||
@@ -522,7 +522,7 @@ asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs) | |||
522 | { | 522 | { |
523 | long long ret = 0; | 523 | long long ret = 0; |
524 | 524 | ||
525 | secure_computing(regs->regs[9]); | 525 | secure_computing_strict(regs->regs[9]); |
526 | 526 | ||
527 | if (test_thread_flag(TIF_SYSCALL_TRACE) && | 527 | if (test_thread_flag(TIF_SYSCALL_TRACE) && |
528 | tracehook_report_syscall_entry(regs)) | 528 | tracehook_report_syscall_entry(regs)) |
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index b2b9daf59051..1ea3fd954756 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -583,6 +583,9 @@ config SYSVIPC_COMPAT | |||
583 | depends on COMPAT && SYSVIPC | 583 | depends on COMPAT && SYSVIPC |
584 | default y | 584 | default y |
585 | 585 | ||
586 | config KEYS_COMPAT | ||
587 | def_bool y if COMPAT && KEYS | ||
588 | |||
586 | endmenu | 589 | endmenu |
587 | 590 | ||
588 | source "net/Kconfig" | 591 | source "net/Kconfig" |
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index 6f97c0767995..484dabac7045 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c | |||
@@ -1062,7 +1062,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) | |||
1062 | int ret = 0; | 1062 | int ret = 0; |
1063 | 1063 | ||
1064 | /* do the secure computing check first */ | 1064 | /* do the secure computing check first */ |
1065 | secure_computing(regs->u_regs[UREG_G1]); | 1065 | secure_computing_strict(regs->u_regs[UREG_G1]); |
1066 | 1066 | ||
1067 | if (test_thread_flag(TIF_SYSCALL_TRACE)) | 1067 | if (test_thread_flag(TIF_SYSCALL_TRACE)) |
1068 | ret = tracehook_report_syscall_entry(regs); | 1068 | ret = tracehook_report_syscall_entry(regs); |
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index db86b1a0e9a9..3a58e0d66f51 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S | |||
@@ -74,7 +74,7 @@ sys_call_table32: | |||
74 | .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy | 74 | .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy |
75 | /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink | 75 | /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink |
76 | .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid | 76 | .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid |
77 | /*280*/ .word sys32_tee, sys_add_key, sys_request_key, sys_keyctl, compat_sys_openat | 77 | /*280*/ .word sys32_tee, sys_add_key, sys_request_key, compat_sys_keyctl, compat_sys_openat |
78 | .word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64 | 78 | .word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64 |
79 | /*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat | 79 | /*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat |
80 | .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare | 80 | .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index c940cb6f0409..2787fbec7aed 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -83,6 +83,7 @@ config X86 | |||
83 | select GENERIC_IOMAP | 83 | select GENERIC_IOMAP |
84 | select DCACHE_WORD_ACCESS | 84 | select DCACHE_WORD_ACCESS |
85 | select GENERIC_SMP_IDLE_THREAD | 85 | select GENERIC_SMP_IDLE_THREAD |
86 | select HAVE_ARCH_SECCOMP_FILTER | ||
86 | 87 | ||
87 | config INSTRUCTION_DECODER | 88 | config INSTRUCTION_DECODER |
88 | def_bool (KPROBES || PERF_EVENTS) | 89 | def_bool (KPROBES || PERF_EVENTS) |
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index a69245ba27e3..0b3f2354f6aa 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -67,6 +67,10 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) | |||
67 | switch (from->si_code >> 16) { | 67 | switch (from->si_code >> 16) { |
68 | case __SI_FAULT >> 16: | 68 | case __SI_FAULT >> 16: |
69 | break; | 69 | break; |
70 | case __SI_SYS >> 16: | ||
71 | put_user_ex(from->si_syscall, &to->si_syscall); | ||
72 | put_user_ex(from->si_arch, &to->si_arch); | ||
73 | break; | ||
70 | case __SI_CHLD >> 16: | 74 | case __SI_CHLD >> 16: |
71 | if (ia32) { | 75 | if (ia32) { |
72 | put_user_ex(from->si_utime, &to->si_utime); | 76 | put_user_ex(from->si_utime, &to->si_utime); |
diff --git a/arch/x86/include/asm/ia32.h b/arch/x86/include/asm/ia32.h index ee52760549f0..b04cbdb138cd 100644 --- a/arch/x86/include/asm/ia32.h +++ b/arch/x86/include/asm/ia32.h | |||
@@ -144,6 +144,12 @@ typedef struct compat_siginfo { | |||
144 | int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ | 144 | int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ |
145 | int _fd; | 145 | int _fd; |
146 | } _sigpoll; | 146 | } _sigpoll; |
147 | |||
148 | struct { | ||
149 | unsigned int _call_addr; /* calling insn */ | ||
150 | int _syscall; /* triggering system call number */ | ||
151 | unsigned int _arch; /* AUDIT_ARCH_* of syscall */ | ||
152 | } _sigsys; | ||
147 | } _sifields; | 153 | } _sifields; |
148 | } compat_siginfo_t; | 154 | } compat_siginfo_t; |
149 | 155 | ||
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index 386b78686c4d..1ace47b62592 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h | |||
@@ -13,9 +13,11 @@ | |||
13 | #ifndef _ASM_X86_SYSCALL_H | 13 | #ifndef _ASM_X86_SYSCALL_H |
14 | #define _ASM_X86_SYSCALL_H | 14 | #define _ASM_X86_SYSCALL_H |
15 | 15 | ||
16 | #include <linux/audit.h> | ||
16 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
17 | #include <linux/err.h> | 18 | #include <linux/err.h> |
18 | #include <asm/asm-offsets.h> /* For NR_syscalls */ | 19 | #include <asm/asm-offsets.h> /* For NR_syscalls */ |
20 | #include <asm/thread_info.h> /* for TS_COMPAT */ | ||
19 | #include <asm/unistd.h> | 21 | #include <asm/unistd.h> |
20 | 22 | ||
21 | extern const unsigned long sys_call_table[]; | 23 | extern const unsigned long sys_call_table[]; |
@@ -88,6 +90,12 @@ static inline void syscall_set_arguments(struct task_struct *task, | |||
88 | memcpy(®s->bx + i, args, n * sizeof(args[0])); | 90 | memcpy(®s->bx + i, args, n * sizeof(args[0])); |
89 | } | 91 | } |
90 | 92 | ||
93 | static inline int syscall_get_arch(struct task_struct *task, | ||
94 | struct pt_regs *regs) | ||
95 | { | ||
96 | return AUDIT_ARCH_I386; | ||
97 | } | ||
98 | |||
91 | #else /* CONFIG_X86_64 */ | 99 | #else /* CONFIG_X86_64 */ |
92 | 100 | ||
93 | static inline void syscall_get_arguments(struct task_struct *task, | 101 | static inline void syscall_get_arguments(struct task_struct *task, |
@@ -212,6 +220,25 @@ static inline void syscall_set_arguments(struct task_struct *task, | |||
212 | } | 220 | } |
213 | } | 221 | } |
214 | 222 | ||
223 | static inline int syscall_get_arch(struct task_struct *task, | ||
224 | struct pt_regs *regs) | ||
225 | { | ||
226 | #ifdef CONFIG_IA32_EMULATION | ||
227 | /* | ||
228 | * TS_COMPAT is set for 32-bit syscall entry and then | ||
229 | * remains set until we return to user mode. | ||
230 | * | ||
231 | * TIF_IA32 tasks should always have TS_COMPAT set at | ||
232 | * system call time. | ||
233 | * | ||
234 | * x32 tasks should be considered AUDIT_ARCH_X86_64. | ||
235 | */ | ||
236 | if (task_thread_info(task)->status & TS_COMPAT) | ||
237 | return AUDIT_ARCH_I386; | ||
238 | #endif | ||
239 | /* Both x32 and x86_64 are considered "64-bit". */ | ||
240 | return AUDIT_ARCH_X86_64; | ||
241 | } | ||
215 | #endif /* CONFIG_X86_32 */ | 242 | #endif /* CONFIG_X86_32 */ |
216 | 243 | ||
217 | #endif /* _ASM_X86_SYSCALL_H */ | 244 | #endif /* _ASM_X86_SYSCALL_H */ |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 685845cf16e0..13b1990c7c58 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -1480,7 +1480,11 @@ long syscall_trace_enter(struct pt_regs *regs) | |||
1480 | regs->flags |= X86_EFLAGS_TF; | 1480 | regs->flags |= X86_EFLAGS_TF; |
1481 | 1481 | ||
1482 | /* do the secure computing check first */ | 1482 | /* do the secure computing check first */ |
1483 | secure_computing(regs->orig_ax); | 1483 | if (secure_computing(regs->orig_ax)) { |
1484 | /* seccomp failures shouldn't expose any additional code. */ | ||
1485 | ret = -1L; | ||
1486 | goto out; | ||
1487 | } | ||
1484 | 1488 | ||
1485 | if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) | 1489 | if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) |
1486 | ret = -1L; | 1490 | ret = -1L; |
@@ -1505,6 +1509,7 @@ long syscall_trace_enter(struct pt_regs *regs) | |||
1505 | regs->dx, regs->r10); | 1509 | regs->dx, regs->r10); |
1506 | #endif | 1510 | #endif |
1507 | 1511 | ||
1512 | out: | ||
1508 | return ret ?: regs->orig_ax; | 1513 | return ret ?: regs->orig_ax; |
1509 | } | 1514 | } |
1510 | 1515 | ||
@@ -1245,6 +1245,13 @@ static int check_unsafe_exec(struct linux_binprm *bprm) | |||
1245 | bprm->unsafe |= LSM_UNSAFE_PTRACE; | 1245 | bprm->unsafe |= LSM_UNSAFE_PTRACE; |
1246 | } | 1246 | } |
1247 | 1247 | ||
1248 | /* | ||
1249 | * This isn't strictly necessary, but it makes it harder for LSMs to | ||
1250 | * mess up. | ||
1251 | */ | ||
1252 | if (current->no_new_privs) | ||
1253 | bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS; | ||
1254 | |||
1248 | n_fs = 1; | 1255 | n_fs = 1; |
1249 | spin_lock(&p->fs->lock); | 1256 | spin_lock(&p->fs->lock); |
1250 | rcu_read_lock(); | 1257 | rcu_read_lock(); |
@@ -1288,7 +1295,8 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1288 | bprm->cred->euid = current_euid(); | 1295 | bprm->cred->euid = current_euid(); |
1289 | bprm->cred->egid = current_egid(); | 1296 | bprm->cred->egid = current_egid(); |
1290 | 1297 | ||
1291 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { | 1298 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) && |
1299 | !current->no_new_privs) { | ||
1292 | /* Set-uid? */ | 1300 | /* Set-uid? */ |
1293 | if (mode & S_ISUID) { | 1301 | if (mode & S_ISUID) { |
1294 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 1302 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
@@ -681,7 +681,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
681 | 681 | ||
682 | f->f_op = fops_get(inode->i_fop); | 682 | f->f_op = fops_get(inode->i_fop); |
683 | 683 | ||
684 | error = security_dentry_open(f, cred); | 684 | error = security_file_open(f, cred); |
685 | if (error) | 685 | if (error) |
686 | goto cleanup_all; | 686 | goto cleanup_all; |
687 | 687 | ||
diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h index 5e5e3865f1ed..8ed67779fc09 100644 --- a/include/asm-generic/siginfo.h +++ b/include/asm-generic/siginfo.h | |||
@@ -98,9 +98,18 @@ typedef struct siginfo { | |||
98 | __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ | 98 | __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ |
99 | int _fd; | 99 | int _fd; |
100 | } _sigpoll; | 100 | } _sigpoll; |
101 | |||
102 | /* SIGSYS */ | ||
103 | struct { | ||
104 | void __user *_call_addr; /* calling user insn */ | ||
105 | int _syscall; /* triggering system call number */ | ||
106 | unsigned int _arch; /* AUDIT_ARCH_* of syscall */ | ||
107 | } _sigsys; | ||
101 | } _sifields; | 108 | } _sifields; |
102 | } __ARCH_SI_ATTRIBUTES siginfo_t; | 109 | } __ARCH_SI_ATTRIBUTES siginfo_t; |
103 | 110 | ||
111 | /* If the arch shares siginfo, then it has SIGSYS. */ | ||
112 | #define __ARCH_SIGSYS | ||
104 | #endif | 113 | #endif |
105 | 114 | ||
106 | /* | 115 | /* |
@@ -124,6 +133,11 @@ typedef struct siginfo { | |||
124 | #define si_addr_lsb _sifields._sigfault._addr_lsb | 133 | #define si_addr_lsb _sifields._sigfault._addr_lsb |
125 | #define si_band _sifields._sigpoll._band | 134 | #define si_band _sifields._sigpoll._band |
126 | #define si_fd _sifields._sigpoll._fd | 135 | #define si_fd _sifields._sigpoll._fd |
136 | #ifdef __ARCH_SIGSYS | ||
137 | #define si_call_addr _sifields._sigsys._call_addr | ||
138 | #define si_syscall _sifields._sigsys._syscall | ||
139 | #define si_arch _sifields._sigsys._arch | ||
140 | #endif | ||
127 | 141 | ||
128 | #ifdef __KERNEL__ | 142 | #ifdef __KERNEL__ |
129 | #define __SI_MASK 0xffff0000u | 143 | #define __SI_MASK 0xffff0000u |
@@ -134,6 +148,7 @@ typedef struct siginfo { | |||
134 | #define __SI_CHLD (4 << 16) | 148 | #define __SI_CHLD (4 << 16) |
135 | #define __SI_RT (5 << 16) | 149 | #define __SI_RT (5 << 16) |
136 | #define __SI_MESGQ (6 << 16) | 150 | #define __SI_MESGQ (6 << 16) |
151 | #define __SI_SYS (7 << 16) | ||
137 | #define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) | 152 | #define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) |
138 | #else | 153 | #else |
139 | #define __SI_KILL 0 | 154 | #define __SI_KILL 0 |
@@ -143,6 +158,7 @@ typedef struct siginfo { | |||
143 | #define __SI_CHLD 0 | 158 | #define __SI_CHLD 0 |
144 | #define __SI_RT 0 | 159 | #define __SI_RT 0 |
145 | #define __SI_MESGQ 0 | 160 | #define __SI_MESGQ 0 |
161 | #define __SI_SYS 0 | ||
146 | #define __SI_CODE(T,N) (N) | 162 | #define __SI_CODE(T,N) (N) |
147 | #endif | 163 | #endif |
148 | 164 | ||
@@ -240,6 +256,12 @@ typedef struct siginfo { | |||
240 | #define NSIGPOLL 6 | 256 | #define NSIGPOLL 6 |
241 | 257 | ||
242 | /* | 258 | /* |
259 | * SIGSYS si_codes | ||
260 | */ | ||
261 | #define SYS_SECCOMP (__SI_SYS|1) /* seccomp triggered */ | ||
262 | #define NSIGSYS 1 | ||
263 | |||
264 | /* | ||
243 | * sigevent definitions | 265 | * sigevent definitions |
244 | * | 266 | * |
245 | * It seems likely that SIGEV_THREAD will have to be handled from | 267 | * It seems likely that SIGEV_THREAD will have to be handled from |
diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h index 5c122ae6bfa6..5b09392db673 100644 --- a/include/asm-generic/syscall.h +++ b/include/asm-generic/syscall.h | |||
@@ -142,4 +142,18 @@ void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, | |||
142 | unsigned int i, unsigned int n, | 142 | unsigned int i, unsigned int n, |
143 | const unsigned long *args); | 143 | const unsigned long *args); |
144 | 144 | ||
145 | /** | ||
146 | * syscall_get_arch - return the AUDIT_ARCH for the current system call | ||
147 | * @task: task of interest, must be in system call entry tracing | ||
148 | * @regs: task_pt_regs() of @task | ||
149 | * | ||
150 | * Returns the AUDIT_ARCH_* based on the system call convention in use. | ||
151 | * | ||
152 | * It's only valid to call this when @task is stopped on entry to a system | ||
153 | * call, due to %TIF_SYSCALL_TRACE, %TIF_SYSCALL_AUDIT, or %TIF_SECCOMP. | ||
154 | * | ||
155 | * Architectures which permit CONFIG_HAVE_ARCH_SECCOMP_FILTER must | ||
156 | * provide an implementation of this. | ||
157 | */ | ||
158 | int syscall_get_arch(struct task_struct *task, struct pt_regs *regs); | ||
145 | #endif /* _ASM_SYSCALL_H */ | 159 | #endif /* _ASM_SYSCALL_H */ |
diff --git a/include/keys/keyring-type.h b/include/keys/keyring-type.h index 843f872a4b63..cf49159b0e3a 100644 --- a/include/keys/keyring-type.h +++ b/include/keys/keyring-type.h | |||
@@ -24,7 +24,7 @@ struct keyring_list { | |||
24 | unsigned short maxkeys; /* max keys this list can hold */ | 24 | unsigned short maxkeys; /* max keys this list can hold */ |
25 | unsigned short nkeys; /* number of keys currently held */ | 25 | unsigned short nkeys; /* number of keys currently held */ |
26 | unsigned short delkey; /* key to be unlinked by RCU */ | 26 | unsigned short delkey; /* key to be unlinked by RCU */ |
27 | struct key *keys[0]; | 27 | struct key __rcu *keys[0]; |
28 | }; | 28 | }; |
29 | 29 | ||
30 | 30 | ||
diff --git a/include/linux/Kbuild b/include/linux/Kbuild index b5d568fa19e8..0237b84ba541 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild | |||
@@ -330,6 +330,7 @@ header-y += scc.h | |||
330 | header-y += sched.h | 330 | header-y += sched.h |
331 | header-y += screen_info.h | 331 | header-y += screen_info.h |
332 | header-y += sdla.h | 332 | header-y += sdla.h |
333 | header-y += seccomp.h | ||
333 | header-y += securebits.h | 334 | header-y += securebits.h |
334 | header-y += selinux_netlink.h | 335 | header-y += selinux_netlink.h |
335 | header-y += sem.h | 336 | header-y += sem.h |
diff --git a/include/linux/audit.h b/include/linux/audit.h index ed3ef1972496..22f292a917a3 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -463,7 +463,7 @@ extern void audit_putname(const char *name); | |||
463 | extern void __audit_inode(const char *name, const struct dentry *dentry); | 463 | extern void __audit_inode(const char *name, const struct dentry *dentry); |
464 | extern void __audit_inode_child(const struct dentry *dentry, | 464 | extern void __audit_inode_child(const struct dentry *dentry, |
465 | const struct inode *parent); | 465 | const struct inode *parent); |
466 | extern void __audit_seccomp(unsigned long syscall); | 466 | extern void __audit_seccomp(unsigned long syscall, long signr, int code); |
467 | extern void __audit_ptrace(struct task_struct *t); | 467 | extern void __audit_ptrace(struct task_struct *t); |
468 | 468 | ||
469 | static inline int audit_dummy_context(void) | 469 | static inline int audit_dummy_context(void) |
@@ -508,10 +508,10 @@ static inline void audit_inode_child(const struct dentry *dentry, | |||
508 | } | 508 | } |
509 | void audit_core_dumps(long signr); | 509 | void audit_core_dumps(long signr); |
510 | 510 | ||
511 | static inline void audit_seccomp(unsigned long syscall) | 511 | static inline void audit_seccomp(unsigned long syscall, long signr, int code) |
512 | { | 512 | { |
513 | if (unlikely(!audit_dummy_context())) | 513 | if (unlikely(!audit_dummy_context())) |
514 | __audit_seccomp(syscall); | 514 | __audit_seccomp(syscall, signr, code); |
515 | } | 515 | } |
516 | 516 | ||
517 | static inline void audit_ptrace(struct task_struct *t) | 517 | static inline void audit_ptrace(struct task_struct *t) |
@@ -634,7 +634,7 @@ extern int audit_signals; | |||
634 | #define audit_inode(n,d) do { (void)(d); } while (0) | 634 | #define audit_inode(n,d) do { (void)(d); } while (0) |
635 | #define audit_inode_child(i,p) do { ; } while (0) | 635 | #define audit_inode_child(i,p) do { ; } while (0) |
636 | #define audit_core_dumps(i) do { ; } while (0) | 636 | #define audit_core_dumps(i) do { ; } while (0) |
637 | #define audit_seccomp(i) do { ; } while (0) | 637 | #define audit_seccomp(i,s,c) do { ; } while (0) |
638 | #define auditsc_get_stamp(c,t,s) (0) | 638 | #define auditsc_get_stamp(c,t,s) (0) |
639 | #define audit_get_loginuid(t) (-1) | 639 | #define audit_get_loginuid(t) (-1) |
640 | #define audit_get_sessionid(t) (-1) | 640 | #define audit_get_sessionid(t) (-1) |
diff --git a/include/linux/filter.h b/include/linux/filter.h index 72090994d789..82b01357af8b 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | #ifdef __KERNEL__ | 11 | #ifdef __KERNEL__ |
12 | #include <linux/atomic.h> | 12 | #include <linux/atomic.h> |
13 | #include <linux/compat.h> | ||
13 | #endif | 14 | #endif |
14 | 15 | ||
15 | /* | 16 | /* |
@@ -133,6 +134,16 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */ | |||
133 | 134 | ||
134 | #ifdef __KERNEL__ | 135 | #ifdef __KERNEL__ |
135 | 136 | ||
137 | #ifdef CONFIG_COMPAT | ||
138 | /* | ||
139 | * A struct sock_filter is architecture independent. | ||
140 | */ | ||
141 | struct compat_sock_fprog { | ||
142 | u16 len; | ||
143 | compat_uptr_t filter; /* struct sock_filter * */ | ||
144 | }; | ||
145 | #endif | ||
146 | |||
136 | struct sk_buff; | 147 | struct sk_buff; |
137 | struct sock; | 148 | struct sock; |
138 | 149 | ||
@@ -233,6 +244,7 @@ enum { | |||
233 | BPF_S_ANC_RXHASH, | 244 | BPF_S_ANC_RXHASH, |
234 | BPF_S_ANC_CPU, | 245 | BPF_S_ANC_CPU, |
235 | BPF_S_ANC_ALU_XOR_X, | 246 | BPF_S_ANC_ALU_XOR_X, |
247 | BPF_S_ANC_SECCOMP_LD_W, | ||
236 | }; | 248 | }; |
237 | 249 | ||
238 | #endif /* __KERNEL__ */ | 250 | #endif /* __KERNEL__ */ |
diff --git a/include/linux/key.h b/include/linux/key.h index 96933b1e5d24..5231800770e1 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -124,7 +124,10 @@ static inline unsigned long is_key_possessed(const key_ref_t key_ref) | |||
124 | struct key { | 124 | struct key { |
125 | atomic_t usage; /* number of references */ | 125 | atomic_t usage; /* number of references */ |
126 | key_serial_t serial; /* key serial number */ | 126 | key_serial_t serial; /* key serial number */ |
127 | struct rb_node serial_node; | 127 | union { |
128 | struct list_head graveyard_link; | ||
129 | struct rb_node serial_node; | ||
130 | }; | ||
128 | struct key_type *type; /* type of key */ | 131 | struct key_type *type; /* type of key */ |
129 | struct rw_semaphore sem; /* change vs change sem */ | 132 | struct rw_semaphore sem; /* change vs change sem */ |
130 | struct key_user *user; /* owner of this key */ | 133 | struct key_user *user; /* owner of this key */ |
@@ -133,6 +136,7 @@ struct key { | |||
133 | time_t expiry; /* time at which key expires (or 0) */ | 136 | time_t expiry; /* time at which key expires (or 0) */ |
134 | time_t revoked_at; /* time at which key was revoked */ | 137 | time_t revoked_at; /* time at which key was revoked */ |
135 | }; | 138 | }; |
139 | time_t last_used_at; /* last time used for LRU keyring discard */ | ||
136 | uid_t uid; | 140 | uid_t uid; |
137 | gid_t gid; | 141 | gid_t gid; |
138 | key_perm_t perm; /* access permissions */ | 142 | key_perm_t perm; /* access permissions */ |
@@ -156,6 +160,7 @@ struct key { | |||
156 | #define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */ | 160 | #define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */ |
157 | #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ | 161 | #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ |
158 | #define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ | 162 | #define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ |
163 | #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ | ||
159 | 164 | ||
160 | /* the description string | 165 | /* the description string |
161 | * - this is used to match a key against search criteria | 166 | * - this is used to match a key against search criteria |
@@ -199,6 +204,7 @@ extern struct key *key_alloc(struct key_type *type, | |||
199 | #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ | 204 | #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ |
200 | 205 | ||
201 | extern void key_revoke(struct key *key); | 206 | extern void key_revoke(struct key *key); |
207 | extern void key_invalidate(struct key *key); | ||
202 | extern void key_put(struct key *key); | 208 | extern void key_put(struct key *key); |
203 | 209 | ||
204 | static inline struct key *key_get(struct key *key) | 210 | static inline struct key *key_get(struct key *key) |
@@ -236,7 +242,7 @@ extern struct key *request_key_async_with_auxdata(struct key_type *type, | |||
236 | 242 | ||
237 | extern int wait_for_key_construction(struct key *key, bool intr); | 243 | extern int wait_for_key_construction(struct key *key, bool intr); |
238 | 244 | ||
239 | extern int key_validate(struct key *key); | 245 | extern int key_validate(const struct key *key); |
240 | 246 | ||
241 | extern key_ref_t key_create_or_update(key_ref_t keyring, | 247 | extern key_ref_t key_create_or_update(key_ref_t keyring, |
242 | const char *type, | 248 | const char *type, |
@@ -319,6 +325,7 @@ extern void key_init(void); | |||
319 | #define key_serial(k) 0 | 325 | #define key_serial(k) 0 |
320 | #define key_get(k) ({ NULL; }) | 326 | #define key_get(k) ({ NULL; }) |
321 | #define key_revoke(k) do { } while(0) | 327 | #define key_revoke(k) do { } while(0) |
328 | #define key_invalidate(k) do { } while(0) | ||
322 | #define key_put(k) do { } while(0) | 329 | #define key_put(k) do { } while(0) |
323 | #define key_ref_put(k) do { } while(0) | 330 | #define key_ref_put(k) do { } while(0) |
324 | #define make_key_ref(k, p) NULL | 331 | #define make_key_ref(k, p) NULL |
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h index 9b0b865ce622..c9b7f4faf97a 100644 --- a/include/linux/keyctl.h +++ b/include/linux/keyctl.h | |||
@@ -55,5 +55,6 @@ | |||
55 | #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ | 55 | #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ |
56 | #define KEYCTL_REJECT 19 /* reject a partially constructed key */ | 56 | #define KEYCTL_REJECT 19 /* reject a partially constructed key */ |
57 | #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ | 57 | #define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ |
58 | #define KEYCTL_INVALIDATE 21 /* invalidate a key */ | ||
58 | 59 | ||
59 | #endif /* _LINUX_KEYCTL_H */ | 60 | #endif /* _LINUX_KEYCTL_H */ |
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index fad48aab893b..1cc89e9df480 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h | |||
@@ -53,7 +53,6 @@ struct common_audit_data { | |||
53 | #define LSM_AUDIT_DATA_KMOD 8 | 53 | #define LSM_AUDIT_DATA_KMOD 8 |
54 | #define LSM_AUDIT_DATA_INODE 9 | 54 | #define LSM_AUDIT_DATA_INODE 9 |
55 | #define LSM_AUDIT_DATA_DENTRY 10 | 55 | #define LSM_AUDIT_DATA_DENTRY 10 |
56 | struct task_struct *tsk; | ||
57 | union { | 56 | union { |
58 | struct path path; | 57 | struct path path; |
59 | struct dentry *dentry; | 58 | struct dentry *dentry; |
@@ -93,11 +92,6 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb, | |||
93 | int ipv6_skb_to_auditdata(struct sk_buff *skb, | 92 | int ipv6_skb_to_auditdata(struct sk_buff *skb, |
94 | struct common_audit_data *ad, u8 *proto); | 93 | struct common_audit_data *ad, u8 *proto); |
95 | 94 | ||
96 | /* Initialize an LSM audit data structure. */ | ||
97 | #define COMMON_AUDIT_DATA_INIT(_d, _t) \ | ||
98 | { memset((_d), 0, sizeof(struct common_audit_data)); \ | ||
99 | (_d)->type = LSM_AUDIT_DATA_##_t; } | ||
100 | |||
101 | void common_lsm_audit(struct common_audit_data *a, | 95 | void common_lsm_audit(struct common_audit_data *a, |
102 | void (*pre_audit)(struct audit_buffer *, void *), | 96 | void (*pre_audit)(struct audit_buffer *, void *), |
103 | void (*post_audit)(struct audit_buffer *, void *)); | 97 | void (*post_audit)(struct audit_buffer *, void *)); |
diff --git a/include/linux/prctl.h b/include/linux/prctl.h index e0cfec2490aa..78b76e24cc7e 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h | |||
@@ -124,4 +124,19 @@ | |||
124 | #define PR_SET_CHILD_SUBREAPER 36 | 124 | #define PR_SET_CHILD_SUBREAPER 36 |
125 | #define PR_GET_CHILD_SUBREAPER 37 | 125 | #define PR_GET_CHILD_SUBREAPER 37 |
126 | 126 | ||
127 | /* | ||
128 | * If no_new_privs is set, then operations that grant new privileges (i.e. | ||
129 | * execve) will either fail or not grant them. This affects suid/sgid, | ||
130 | * file capabilities, and LSMs. | ||
131 | * | ||
132 | * Operations that merely manipulate or drop existing privileges (setresuid, | ||
133 | * capset, etc.) will still work. Drop those privileges if you want them gone. | ||
134 | * | ||
135 | * Changing LSM security domain is considered a new privilege. So, for example, | ||
136 | * asking selinux for a specific new context (e.g. with runcon) will result | ||
137 | * in execve returning -EPERM. | ||
138 | */ | ||
139 | #define PR_SET_NO_NEW_PRIVS 38 | ||
140 | #define PR_GET_NO_NEW_PRIVS 39 | ||
141 | |||
127 | #endif /* _LINUX_PRCTL_H */ | 142 | #endif /* _LINUX_PRCTL_H */ |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 5c719627c2aa..597e4fdb97fe 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -58,6 +58,7 @@ | |||
58 | #define PTRACE_EVENT_EXEC 4 | 58 | #define PTRACE_EVENT_EXEC 4 |
59 | #define PTRACE_EVENT_VFORK_DONE 5 | 59 | #define PTRACE_EVENT_VFORK_DONE 5 |
60 | #define PTRACE_EVENT_EXIT 6 | 60 | #define PTRACE_EVENT_EXIT 6 |
61 | #define PTRACE_EVENT_SECCOMP 7 | ||
61 | /* Extended result codes which enabled by means other than options. */ | 62 | /* Extended result codes which enabled by means other than options. */ |
62 | #define PTRACE_EVENT_STOP 128 | 63 | #define PTRACE_EVENT_STOP 128 |
63 | 64 | ||
@@ -69,8 +70,9 @@ | |||
69 | #define PTRACE_O_TRACEEXEC (1 << PTRACE_EVENT_EXEC) | 70 | #define PTRACE_O_TRACEEXEC (1 << PTRACE_EVENT_EXEC) |
70 | #define PTRACE_O_TRACEVFORKDONE (1 << PTRACE_EVENT_VFORK_DONE) | 71 | #define PTRACE_O_TRACEVFORKDONE (1 << PTRACE_EVENT_VFORK_DONE) |
71 | #define PTRACE_O_TRACEEXIT (1 << PTRACE_EVENT_EXIT) | 72 | #define PTRACE_O_TRACEEXIT (1 << PTRACE_EVENT_EXIT) |
73 | #define PTRACE_O_TRACESECCOMP (1 << PTRACE_EVENT_SECCOMP) | ||
72 | 74 | ||
73 | #define PTRACE_O_MASK 0x0000007f | 75 | #define PTRACE_O_MASK 0x000000ff |
74 | 76 | ||
75 | #include <asm/ptrace.h> | 77 | #include <asm/ptrace.h> |
76 | 78 | ||
@@ -98,6 +100,7 @@ | |||
98 | #define PT_TRACE_EXEC PT_EVENT_FLAG(PTRACE_EVENT_EXEC) | 100 | #define PT_TRACE_EXEC PT_EVENT_FLAG(PTRACE_EVENT_EXEC) |
99 | #define PT_TRACE_VFORK_DONE PT_EVENT_FLAG(PTRACE_EVENT_VFORK_DONE) | 101 | #define PT_TRACE_VFORK_DONE PT_EVENT_FLAG(PTRACE_EVENT_VFORK_DONE) |
100 | #define PT_TRACE_EXIT PT_EVENT_FLAG(PTRACE_EVENT_EXIT) | 102 | #define PT_TRACE_EXIT PT_EVENT_FLAG(PTRACE_EVENT_EXIT) |
103 | #define PT_TRACE_SECCOMP PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP) | ||
101 | 104 | ||
102 | /* single stepping state bits (used on ARM and PA-RISC) */ | 105 | /* single stepping state bits (used on ARM and PA-RISC) */ |
103 | #define PT_SINGLESTEP_BIT 31 | 106 | #define PT_SINGLESTEP_BIT 31 |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 8f3fd945070f..f774d88cd0aa 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1341,6 +1341,8 @@ struct task_struct { | |||
1341 | * execve */ | 1341 | * execve */ |
1342 | unsigned in_iowait:1; | 1342 | unsigned in_iowait:1; |
1343 | 1343 | ||
1344 | /* task may not gain privileges */ | ||
1345 | unsigned no_new_privs:1; | ||
1344 | 1346 | ||
1345 | /* Revert to default priority/policy when forking */ | 1347 | /* Revert to default priority/policy when forking */ |
1346 | unsigned sched_reset_on_fork:1; | 1348 | unsigned sched_reset_on_fork:1; |
@@ -1450,7 +1452,7 @@ struct task_struct { | |||
1450 | uid_t loginuid; | 1452 | uid_t loginuid; |
1451 | unsigned int sessionid; | 1453 | unsigned int sessionid; |
1452 | #endif | 1454 | #endif |
1453 | seccomp_t seccomp; | 1455 | struct seccomp seccomp; |
1454 | 1456 | ||
1455 | /* Thread group tracking */ | 1457 | /* Thread group tracking */ |
1456 | u32 parent_exec_id; | 1458 | u32 parent_exec_id; |
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index cc7a4e9cc7ad..84f6320da50f 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h | |||
@@ -1,25 +1,90 @@ | |||
1 | #ifndef _LINUX_SECCOMP_H | 1 | #ifndef _LINUX_SECCOMP_H |
2 | #define _LINUX_SECCOMP_H | 2 | #define _LINUX_SECCOMP_H |
3 | 3 | ||
4 | 4 | #include <linux/compiler.h> | |
5 | #include <linux/types.h> | ||
6 | |||
7 | |||
8 | /* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, <mode>) */ | ||
9 | #define SECCOMP_MODE_DISABLED 0 /* seccomp is not in use. */ | ||
10 | #define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ | ||
11 | #define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ | ||
12 | |||
13 | /* | ||
14 | * All BPF programs must return a 32-bit value. | ||
15 | * The bottom 16-bits are for optional return data. | ||
16 | * The upper 16-bits are ordered from least permissive values to most. | ||
17 | * | ||
18 | * The ordering ensures that a min_t() over composed return values always | ||
19 | * selects the least permissive choice. | ||
20 | */ | ||
21 | #define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ | ||
22 | #define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ | ||
23 | #define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ | ||
24 | #define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ | ||
25 | #define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ | ||
26 | |||
27 | /* Masks for the return value sections. */ | ||
28 | #define SECCOMP_RET_ACTION 0x7fff0000U | ||
29 | #define SECCOMP_RET_DATA 0x0000ffffU | ||
30 | |||
31 | /** | ||
32 | * struct seccomp_data - the format the BPF program executes over. | ||
33 | * @nr: the system call number | ||
34 | * @arch: indicates system call convention as an AUDIT_ARCH_* value | ||
35 | * as defined in <linux/audit.h>. | ||
36 | * @instruction_pointer: at the time of the system call. | ||
37 | * @args: up to 6 system call arguments always stored as 64-bit values | ||
38 | * regardless of the architecture. | ||
39 | */ | ||
40 | struct seccomp_data { | ||
41 | int nr; | ||
42 | __u32 arch; | ||
43 | __u64 instruction_pointer; | ||
44 | __u64 args[6]; | ||
45 | }; | ||
46 | |||
47 | #ifdef __KERNEL__ | ||
5 | #ifdef CONFIG_SECCOMP | 48 | #ifdef CONFIG_SECCOMP |
6 | 49 | ||
7 | #include <linux/thread_info.h> | 50 | #include <linux/thread_info.h> |
8 | #include <asm/seccomp.h> | 51 | #include <asm/seccomp.h> |
9 | 52 | ||
10 | typedef struct { int mode; } seccomp_t; | 53 | struct seccomp_filter; |
11 | 54 | /** | |
12 | extern void __secure_computing(int); | 55 | * struct seccomp - the state of a seccomp'ed process |
13 | static inline void secure_computing(int this_syscall) | 56 | * |
57 | * @mode: indicates one of the valid values above for controlled | ||
58 | * system calls available to a process. | ||
59 | * @filter: The metadata and ruleset for determining what system calls | ||
60 | * are allowed for a task. | ||
61 | * | ||
62 | * @filter must only be accessed from the context of current as there | ||
63 | * is no locking. | ||
64 | */ | ||
65 | struct seccomp { | ||
66 | int mode; | ||
67 | struct seccomp_filter *filter; | ||
68 | }; | ||
69 | |||
70 | extern int __secure_computing(int); | ||
71 | static inline int secure_computing(int this_syscall) | ||
14 | { | 72 | { |
15 | if (unlikely(test_thread_flag(TIF_SECCOMP))) | 73 | if (unlikely(test_thread_flag(TIF_SECCOMP))) |
16 | __secure_computing(this_syscall); | 74 | return __secure_computing(this_syscall); |
75 | return 0; | ||
76 | } | ||
77 | |||
78 | /* A wrapper for architectures supporting only SECCOMP_MODE_STRICT. */ | ||
79 | static inline void secure_computing_strict(int this_syscall) | ||
80 | { | ||
81 | BUG_ON(secure_computing(this_syscall) != 0); | ||
17 | } | 82 | } |
18 | 83 | ||
19 | extern long prctl_get_seccomp(void); | 84 | extern long prctl_get_seccomp(void); |
20 | extern long prctl_set_seccomp(unsigned long); | 85 | extern long prctl_set_seccomp(unsigned long, char __user *); |
21 | 86 | ||
22 | static inline int seccomp_mode(seccomp_t *s) | 87 | static inline int seccomp_mode(struct seccomp *s) |
23 | { | 88 | { |
24 | return s->mode; | 89 | return s->mode; |
25 | } | 90 | } |
@@ -28,25 +93,41 @@ static inline int seccomp_mode(seccomp_t *s) | |||
28 | 93 | ||
29 | #include <linux/errno.h> | 94 | #include <linux/errno.h> |
30 | 95 | ||
31 | typedef struct { } seccomp_t; | 96 | struct seccomp { }; |
97 | struct seccomp_filter { }; | ||
32 | 98 | ||
33 | #define secure_computing(x) do { } while (0) | 99 | static inline int secure_computing(int this_syscall) { return 0; } |
100 | static inline void secure_computing_strict(int this_syscall) { return; } | ||
34 | 101 | ||
35 | static inline long prctl_get_seccomp(void) | 102 | static inline long prctl_get_seccomp(void) |
36 | { | 103 | { |
37 | return -EINVAL; | 104 | return -EINVAL; |
38 | } | 105 | } |
39 | 106 | ||
40 | static inline long prctl_set_seccomp(unsigned long arg2) | 107 | static inline long prctl_set_seccomp(unsigned long arg2, char __user *arg3) |
41 | { | 108 | { |
42 | return -EINVAL; | 109 | return -EINVAL; |
43 | } | 110 | } |
44 | 111 | ||
45 | static inline int seccomp_mode(seccomp_t *s) | 112 | static inline int seccomp_mode(struct seccomp *s) |
46 | { | 113 | { |
47 | return 0; | 114 | return 0; |
48 | } | 115 | } |
49 | |||
50 | #endif /* CONFIG_SECCOMP */ | 116 | #endif /* CONFIG_SECCOMP */ |
51 | 117 | ||
118 | #ifdef CONFIG_SECCOMP_FILTER | ||
119 | extern void put_seccomp_filter(struct task_struct *tsk); | ||
120 | extern void get_seccomp_filter(struct task_struct *tsk); | ||
121 | extern u32 seccomp_bpf_load(int off); | ||
122 | #else /* CONFIG_SECCOMP_FILTER */ | ||
123 | static inline void put_seccomp_filter(struct task_struct *tsk) | ||
124 | { | ||
125 | return; | ||
126 | } | ||
127 | static inline void get_seccomp_filter(struct task_struct *tsk) | ||
128 | { | ||
129 | return; | ||
130 | } | ||
131 | #endif /* CONFIG_SECCOMP_FILTER */ | ||
132 | #endif /* __KERNEL__ */ | ||
52 | #endif /* _LINUX_SECCOMP_H */ | 133 | #endif /* _LINUX_SECCOMP_H */ |
diff --git a/include/linux/security.h b/include/linux/security.h index 673afbb8238a..ab0e091ce5fa 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -144,6 +144,7 @@ struct request_sock; | |||
144 | #define LSM_UNSAFE_SHARE 1 | 144 | #define LSM_UNSAFE_SHARE 1 |
145 | #define LSM_UNSAFE_PTRACE 2 | 145 | #define LSM_UNSAFE_PTRACE 2 |
146 | #define LSM_UNSAFE_PTRACE_CAP 4 | 146 | #define LSM_UNSAFE_PTRACE_CAP 4 |
147 | #define LSM_UNSAFE_NO_NEW_PRIVS 8 | ||
147 | 148 | ||
148 | #ifdef CONFIG_MMU | 149 | #ifdef CONFIG_MMU |
149 | extern int mmap_min_addr_handler(struct ctl_table *table, int write, | 150 | extern int mmap_min_addr_handler(struct ctl_table *table, int write, |
@@ -639,10 +640,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
639 | * to receive an open file descriptor via socket IPC. | 640 | * to receive an open file descriptor via socket IPC. |
640 | * @file contains the file structure being received. | 641 | * @file contains the file structure being received. |
641 | * Return 0 if permission is granted. | 642 | * Return 0 if permission is granted. |
642 | * | 643 | * @file_open |
643 | * Security hook for dentry | ||
644 | * | ||
645 | * @dentry_open | ||
646 | * Save open-time permission checking state for later use upon | 644 | * Save open-time permission checking state for later use upon |
647 | * file_permission, and recheck access if anything has changed | 645 | * file_permission, and recheck access if anything has changed |
648 | * since inode_permission. | 646 | * since inode_permission. |
@@ -1497,7 +1495,7 @@ struct security_operations { | |||
1497 | int (*file_send_sigiotask) (struct task_struct *tsk, | 1495 | int (*file_send_sigiotask) (struct task_struct *tsk, |
1498 | struct fown_struct *fown, int sig); | 1496 | struct fown_struct *fown, int sig); |
1499 | int (*file_receive) (struct file *file); | 1497 | int (*file_receive) (struct file *file); |
1500 | int (*dentry_open) (struct file *file, const struct cred *cred); | 1498 | int (*file_open) (struct file *file, const struct cred *cred); |
1501 | 1499 | ||
1502 | int (*task_create) (unsigned long clone_flags); | 1500 | int (*task_create) (unsigned long clone_flags); |
1503 | void (*task_free) (struct task_struct *task); | 1501 | void (*task_free) (struct task_struct *task); |
@@ -1756,7 +1754,7 @@ int security_file_set_fowner(struct file *file); | |||
1756 | int security_file_send_sigiotask(struct task_struct *tsk, | 1754 | int security_file_send_sigiotask(struct task_struct *tsk, |
1757 | struct fown_struct *fown, int sig); | 1755 | struct fown_struct *fown, int sig); |
1758 | int security_file_receive(struct file *file); | 1756 | int security_file_receive(struct file *file); |
1759 | int security_dentry_open(struct file *file, const struct cred *cred); | 1757 | int security_file_open(struct file *file, const struct cred *cred); |
1760 | int security_task_create(unsigned long clone_flags); | 1758 | int security_task_create(unsigned long clone_flags); |
1761 | void security_task_free(struct task_struct *task); | 1759 | void security_task_free(struct task_struct *task); |
1762 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); | 1760 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); |
@@ -2227,8 +2225,8 @@ static inline int security_file_receive(struct file *file) | |||
2227 | return 0; | 2225 | return 0; |
2228 | } | 2226 | } |
2229 | 2227 | ||
2230 | static inline int security_dentry_open(struct file *file, | 2228 | static inline int security_file_open(struct file *file, |
2231 | const struct cred *cred) | 2229 | const struct cred *cred) |
2232 | { | 2230 | { |
2233 | return 0; | 2231 | return 0; |
2234 | } | 2232 | } |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index af1de0f34eae..4b96415527b8 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -67,6 +67,7 @@ | |||
67 | #include <linux/syscalls.h> | 67 | #include <linux/syscalls.h> |
68 | #include <linux/capability.h> | 68 | #include <linux/capability.h> |
69 | #include <linux/fs_struct.h> | 69 | #include <linux/fs_struct.h> |
70 | #include <linux/compat.h> | ||
70 | 71 | ||
71 | #include "audit.h" | 72 | #include "audit.h" |
72 | 73 | ||
@@ -2710,13 +2711,16 @@ void audit_core_dumps(long signr) | |||
2710 | audit_log_end(ab); | 2711 | audit_log_end(ab); |
2711 | } | 2712 | } |
2712 | 2713 | ||
2713 | void __audit_seccomp(unsigned long syscall) | 2714 | void __audit_seccomp(unsigned long syscall, long signr, int code) |
2714 | { | 2715 | { |
2715 | struct audit_buffer *ab; | 2716 | struct audit_buffer *ab; |
2716 | 2717 | ||
2717 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); | 2718 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); |
2718 | audit_log_abend(ab, "seccomp", SIGKILL); | 2719 | audit_log_abend(ab, "seccomp", signr); |
2719 | audit_log_format(ab, " syscall=%ld", syscall); | 2720 | audit_log_format(ab, " syscall=%ld", syscall); |
2721 | audit_log_format(ab, " compat=%d", is_compat_task()); | ||
2722 | audit_log_format(ab, " ip=0x%lx", KSTK_EIP(current)); | ||
2723 | audit_log_format(ab, " code=0x%x", code); | ||
2720 | audit_log_end(ab); | 2724 | audit_log_end(ab); |
2721 | } | 2725 | } |
2722 | 2726 | ||
diff --git a/kernel/fork.c b/kernel/fork.c index 9f9b296fa6df..ad54c833116a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/cgroup.h> | 34 | #include <linux/cgroup.h> |
35 | #include <linux/security.h> | 35 | #include <linux/security.h> |
36 | #include <linux/hugetlb.h> | 36 | #include <linux/hugetlb.h> |
37 | #include <linux/seccomp.h> | ||
37 | #include <linux/swap.h> | 38 | #include <linux/swap.h> |
38 | #include <linux/syscalls.h> | 39 | #include <linux/syscalls.h> |
39 | #include <linux/jiffies.h> | 40 | #include <linux/jiffies.h> |
@@ -206,6 +207,7 @@ void free_task(struct task_struct *tsk) | |||
206 | free_thread_info(tsk->stack); | 207 | free_thread_info(tsk->stack); |
207 | rt_mutex_debug_task_free(tsk); | 208 | rt_mutex_debug_task_free(tsk); |
208 | ftrace_graph_exit_task(tsk); | 209 | ftrace_graph_exit_task(tsk); |
210 | put_seccomp_filter(tsk); | ||
209 | free_task_struct(tsk); | 211 | free_task_struct(tsk); |
210 | } | 212 | } |
211 | EXPORT_SYMBOL(free_task); | 213 | EXPORT_SYMBOL(free_task); |
@@ -1192,6 +1194,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1192 | goto fork_out; | 1194 | goto fork_out; |
1193 | 1195 | ||
1194 | ftrace_graph_init_task(p); | 1196 | ftrace_graph_init_task(p); |
1197 | get_seccomp_filter(p); | ||
1195 | 1198 | ||
1196 | rt_mutex_init_task(p); | 1199 | rt_mutex_init_task(p); |
1197 | 1200 | ||
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index e8d76c5895ea..ee376beedaf9 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -3,16 +3,357 @@ | |||
3 | * | 3 | * |
4 | * Copyright 2004-2005 Andrea Arcangeli <andrea@cpushare.com> | 4 | * Copyright 2004-2005 Andrea Arcangeli <andrea@cpushare.com> |
5 | * | 5 | * |
6 | * This defines a simple but solid secure-computing mode. | 6 | * Copyright (C) 2012 Google, Inc. |
7 | * Will Drewry <wad@chromium.org> | ||
8 | * | ||
9 | * This defines a simple but solid secure-computing facility. | ||
10 | * | ||
11 | * Mode 1 uses a fixed list of allowed system calls. | ||
12 | * Mode 2 allows user-defined system call filters in the form | ||
13 | * of Berkeley Packet Filters/Linux Socket Filters. | ||
7 | */ | 14 | */ |
8 | 15 | ||
16 | #include <linux/atomic.h> | ||
9 | #include <linux/audit.h> | 17 | #include <linux/audit.h> |
10 | #include <linux/seccomp.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/compat.h> | 18 | #include <linux/compat.h> |
19 | #include <linux/sched.h> | ||
20 | #include <linux/seccomp.h> | ||
13 | 21 | ||
14 | /* #define SECCOMP_DEBUG 1 */ | 22 | /* #define SECCOMP_DEBUG 1 */ |
15 | #define NR_SECCOMP_MODES 1 | 23 | |
24 | #ifdef CONFIG_SECCOMP_FILTER | ||
25 | #include <asm/syscall.h> | ||
26 | #include <linux/filter.h> | ||
27 | #include <linux/ptrace.h> | ||
28 | #include <linux/security.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/tracehook.h> | ||
31 | #include <linux/uaccess.h> | ||
32 | |||
33 | /** | ||
34 | * struct seccomp_filter - container for seccomp BPF programs | ||
35 | * | ||
36 | * @usage: reference count to manage the object lifetime. | ||
37 | * get/put helpers should be used when accessing an instance | ||
38 | * outside of a lifetime-guarded section. In general, this | ||
39 | * is only needed for handling filters shared across tasks. | ||
40 | * @prev: points to a previously installed, or inherited, filter | ||
41 | * @len: the number of instructions in the program | ||
42 | * @insns: the BPF program instructions to evaluate | ||
43 | * | ||
44 | * seccomp_filter objects are organized in a tree linked via the @prev | ||
45 | * pointer. For any task, it appears to be a singly-linked list starting | ||
46 | * with current->seccomp.filter, the most recently attached or inherited filter. | ||
47 | * However, multiple filters may share a @prev node, by way of fork(), which | ||
48 | * results in a unidirectional tree existing in memory. This is similar to | ||
49 | * how namespaces work. | ||
50 | * | ||
51 | * seccomp_filter objects should never be modified after being attached | ||
52 | * to a task_struct (other than @usage). | ||
53 | */ | ||
54 | struct seccomp_filter { | ||
55 | atomic_t usage; | ||
56 | struct seccomp_filter *prev; | ||
57 | unsigned short len; /* Instruction count */ | ||
58 | struct sock_filter insns[]; | ||
59 | }; | ||
60 | |||
61 | /* Limit any path through the tree to 256KB worth of instructions. */ | ||
62 | #define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter)) | ||
63 | |||
64 | /** | ||
65 | * get_u32 - returns a u32 offset into data | ||
66 | * @data: a unsigned 64 bit value | ||
67 | * @index: 0 or 1 to return the first or second 32-bits | ||
68 | * | ||
69 | * This inline exists to hide the length of unsigned long. If a 32-bit | ||
70 | * unsigned long is passed in, it will be extended and the top 32-bits will be | ||
71 | * 0. If it is a 64-bit unsigned long, then whatever data is resident will be | ||
72 | * properly returned. | ||
73 | * | ||
74 | * Endianness is explicitly ignored and left for BPF program authors to manage | ||
75 | * as per the specific architecture. | ||
76 | */ | ||
77 | static inline u32 get_u32(u64 data, int index) | ||
78 | { | ||
79 | return ((u32 *)&data)[index]; | ||
80 | } | ||
81 | |||
82 | /* Helper for bpf_load below. */ | ||
83 | #define BPF_DATA(_name) offsetof(struct seccomp_data, _name) | ||
84 | /** | ||
85 | * bpf_load: checks and returns a pointer to the requested offset | ||
86 | * @off: offset into struct seccomp_data to load from | ||
87 | * | ||
88 | * Returns the requested 32-bits of data. | ||
89 | * seccomp_check_filter() should assure that @off is 32-bit aligned | ||
90 | * and not out of bounds. Failure to do so is a BUG. | ||
91 | */ | ||
92 | u32 seccomp_bpf_load(int off) | ||
93 | { | ||
94 | struct pt_regs *regs = task_pt_regs(current); | ||
95 | if (off == BPF_DATA(nr)) | ||
96 | return syscall_get_nr(current, regs); | ||
97 | if (off == BPF_DATA(arch)) | ||
98 | return syscall_get_arch(current, regs); | ||
99 | if (off >= BPF_DATA(args[0]) && off < BPF_DATA(args[6])) { | ||
100 | unsigned long value; | ||
101 | int arg = (off - BPF_DATA(args[0])) / sizeof(u64); | ||
102 | int index = !!(off % sizeof(u64)); | ||
103 | syscall_get_arguments(current, regs, arg, 1, &value); | ||
104 | return get_u32(value, index); | ||
105 | } | ||
106 | if (off == BPF_DATA(instruction_pointer)) | ||
107 | return get_u32(KSTK_EIP(current), 0); | ||
108 | if (off == BPF_DATA(instruction_pointer) + sizeof(u32)) | ||
109 | return get_u32(KSTK_EIP(current), 1); | ||
110 | /* seccomp_check_filter should make this impossible. */ | ||
111 | BUG(); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * seccomp_check_filter - verify seccomp filter code | ||
116 | * @filter: filter to verify | ||
117 | * @flen: length of filter | ||
118 | * | ||
119 | * Takes a previously checked filter (by sk_chk_filter) and | ||
120 | * redirects all filter code that loads struct sk_buff data | ||
121 | * and related data through seccomp_bpf_load. It also | ||
122 | * enforces length and alignment checking of those loads. | ||
123 | * | ||
124 | * Returns 0 if the rule set is legal or -EINVAL if not. | ||
125 | */ | ||
126 | static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) | ||
127 | { | ||
128 | int pc; | ||
129 | for (pc = 0; pc < flen; pc++) { | ||
130 | struct sock_filter *ftest = &filter[pc]; | ||
131 | u16 code = ftest->code; | ||
132 | u32 k = ftest->k; | ||
133 | |||
134 | switch (code) { | ||
135 | case BPF_S_LD_W_ABS: | ||
136 | ftest->code = BPF_S_ANC_SECCOMP_LD_W; | ||
137 | /* 32-bit aligned and not out of bounds. */ | ||
138 | if (k >= sizeof(struct seccomp_data) || k & 3) | ||
139 | return -EINVAL; | ||
140 | continue; | ||
141 | case BPF_S_LD_W_LEN: | ||
142 | ftest->code = BPF_S_LD_IMM; | ||
143 | ftest->k = sizeof(struct seccomp_data); | ||
144 | continue; | ||
145 | case BPF_S_LDX_W_LEN: | ||
146 | ftest->code = BPF_S_LDX_IMM; | ||
147 | ftest->k = sizeof(struct seccomp_data); | ||
148 | continue; | ||
149 | /* Explicitly include allowed calls. */ | ||
150 | case BPF_S_RET_K: | ||
151 | case BPF_S_RET_A: | ||
152 | case BPF_S_ALU_ADD_K: | ||
153 | case BPF_S_ALU_ADD_X: | ||
154 | case BPF_S_ALU_SUB_K: | ||
155 | case BPF_S_ALU_SUB_X: | ||
156 | case BPF_S_ALU_MUL_K: | ||
157 | case BPF_S_ALU_MUL_X: | ||
158 | case BPF_S_ALU_DIV_X: | ||
159 | case BPF_S_ALU_AND_K: | ||
160 | case BPF_S_ALU_AND_X: | ||
161 | case BPF_S_ALU_OR_K: | ||
162 | case BPF_S_ALU_OR_X: | ||
163 | case BPF_S_ALU_LSH_K: | ||
164 | case BPF_S_ALU_LSH_X: | ||
165 | case BPF_S_ALU_RSH_K: | ||
166 | case BPF_S_ALU_RSH_X: | ||
167 | case BPF_S_ALU_NEG: | ||
168 | case BPF_S_LD_IMM: | ||
169 | case BPF_S_LDX_IMM: | ||
170 | case BPF_S_MISC_TAX: | ||
171 | case BPF_S_MISC_TXA: | ||
172 | case BPF_S_ALU_DIV_K: | ||
173 | case BPF_S_LD_MEM: | ||
174 | case BPF_S_LDX_MEM: | ||
175 | case BPF_S_ST: | ||
176 | case BPF_S_STX: | ||
177 | case BPF_S_JMP_JA: | ||
178 | case BPF_S_JMP_JEQ_K: | ||
179 | case BPF_S_JMP_JEQ_X: | ||
180 | case BPF_S_JMP_JGE_K: | ||
181 | case BPF_S_JMP_JGE_X: | ||
182 | case BPF_S_JMP_JGT_K: | ||
183 | case BPF_S_JMP_JGT_X: | ||
184 | case BPF_S_JMP_JSET_K: | ||
185 | case BPF_S_JMP_JSET_X: | ||
186 | continue; | ||
187 | default: | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * seccomp_run_filters - evaluates all seccomp filters against @syscall | ||
196 | * @syscall: number of the current system call | ||
197 | * | ||
198 | * Returns valid seccomp BPF response codes. | ||
199 | */ | ||
200 | static u32 seccomp_run_filters(int syscall) | ||
201 | { | ||
202 | struct seccomp_filter *f; | ||
203 | u32 ret = SECCOMP_RET_ALLOW; | ||
204 | |||
205 | /* Ensure unexpected behavior doesn't result in failing open. */ | ||
206 | if (WARN_ON(current->seccomp.filter == NULL)) | ||
207 | return SECCOMP_RET_KILL; | ||
208 | |||
209 | /* | ||
210 | * All filters in the list are evaluated and the lowest BPF return | ||
211 | * value always takes priority (ignoring the DATA). | ||
212 | */ | ||
213 | for (f = current->seccomp.filter; f; f = f->prev) { | ||
214 | u32 cur_ret = sk_run_filter(NULL, f->insns); | ||
215 | if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) | ||
216 | ret = cur_ret; | ||
217 | } | ||
218 | return ret; | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * seccomp_attach_filter: Attaches a seccomp filter to current. | ||
223 | * @fprog: BPF program to install | ||
224 | * | ||
225 | * Returns 0 on success or an errno on failure. | ||
226 | */ | ||
227 | static long seccomp_attach_filter(struct sock_fprog *fprog) | ||
228 | { | ||
229 | struct seccomp_filter *filter; | ||
230 | unsigned long fp_size = fprog->len * sizeof(struct sock_filter); | ||
231 | unsigned long total_insns = fprog->len; | ||
232 | long ret; | ||
233 | |||
234 | if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) | ||
235 | return -EINVAL; | ||
236 | |||
237 | for (filter = current->seccomp.filter; filter; filter = filter->prev) | ||
238 | total_insns += filter->len + 4; /* include a 4 instr penalty */ | ||
239 | if (total_insns > MAX_INSNS_PER_PATH) | ||
240 | return -ENOMEM; | ||
241 | |||
242 | /* | ||
243 | * Installing a seccomp filter requires that the task have | ||
244 | * CAP_SYS_ADMIN in its namespace or be running with no_new_privs. | ||
245 | * This avoids scenarios where unprivileged tasks can affect the | ||
246 | * behavior of privileged children. | ||
247 | */ | ||
248 | if (!current->no_new_privs && | ||
249 | security_capable_noaudit(current_cred(), current_user_ns(), | ||
250 | CAP_SYS_ADMIN) != 0) | ||
251 | return -EACCES; | ||
252 | |||
253 | /* Allocate a new seccomp_filter */ | ||
254 | filter = kzalloc(sizeof(struct seccomp_filter) + fp_size, | ||
255 | GFP_KERNEL|__GFP_NOWARN); | ||
256 | if (!filter) | ||
257 | return -ENOMEM; | ||
258 | atomic_set(&filter->usage, 1); | ||
259 | filter->len = fprog->len; | ||
260 | |||
261 | /* Copy the instructions from fprog. */ | ||
262 | ret = -EFAULT; | ||
263 | if (copy_from_user(filter->insns, fprog->filter, fp_size)) | ||
264 | goto fail; | ||
265 | |||
266 | /* Check and rewrite the fprog via the skb checker */ | ||
267 | ret = sk_chk_filter(filter->insns, filter->len); | ||
268 | if (ret) | ||
269 | goto fail; | ||
270 | |||
271 | /* Check and rewrite the fprog for seccomp use */ | ||
272 | ret = seccomp_check_filter(filter->insns, filter->len); | ||
273 | if (ret) | ||
274 | goto fail; | ||
275 | |||
276 | /* | ||
277 | * If there is an existing filter, make it the prev and don't drop its | ||
278 | * task reference. | ||
279 | */ | ||
280 | filter->prev = current->seccomp.filter; | ||
281 | current->seccomp.filter = filter; | ||
282 | return 0; | ||
283 | fail: | ||
284 | kfree(filter); | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * seccomp_attach_user_filter - attaches a user-supplied sock_fprog | ||
290 | * @user_filter: pointer to the user data containing a sock_fprog. | ||
291 | * | ||
292 | * Returns 0 on success and non-zero otherwise. | ||
293 | */ | ||
294 | long seccomp_attach_user_filter(char __user *user_filter) | ||
295 | { | ||
296 | struct sock_fprog fprog; | ||
297 | long ret = -EFAULT; | ||
298 | |||
299 | #ifdef CONFIG_COMPAT | ||
300 | if (is_compat_task()) { | ||
301 | struct compat_sock_fprog fprog32; | ||
302 | if (copy_from_user(&fprog32, user_filter, sizeof(fprog32))) | ||
303 | goto out; | ||
304 | fprog.len = fprog32.len; | ||
305 | fprog.filter = compat_ptr(fprog32.filter); | ||
306 | } else /* falls through to the if below. */ | ||
307 | #endif | ||
308 | if (copy_from_user(&fprog, user_filter, sizeof(fprog))) | ||
309 | goto out; | ||
310 | ret = seccomp_attach_filter(&fprog); | ||
311 | out: | ||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | /* get_seccomp_filter - increments the reference count of the filter on @tsk */ | ||
316 | void get_seccomp_filter(struct task_struct *tsk) | ||
317 | { | ||
318 | struct seccomp_filter *orig = tsk->seccomp.filter; | ||
319 | if (!orig) | ||
320 | return; | ||
321 | /* Reference count is bounded by the number of total processes. */ | ||
322 | atomic_inc(&orig->usage); | ||
323 | } | ||
324 | |||
325 | /* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */ | ||
326 | void put_seccomp_filter(struct task_struct *tsk) | ||
327 | { | ||
328 | struct seccomp_filter *orig = tsk->seccomp.filter; | ||
329 | /* Clean up single-reference branches iteratively. */ | ||
330 | while (orig && atomic_dec_and_test(&orig->usage)) { | ||
331 | struct seccomp_filter *freeme = orig; | ||
332 | orig = orig->prev; | ||
333 | kfree(freeme); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * seccomp_send_sigsys - signals the task to allow in-process syscall emulation | ||
339 | * @syscall: syscall number to send to userland | ||
340 | * @reason: filter-supplied reason code to send to userland (via si_errno) | ||
341 | * | ||
342 | * Forces a SIGSYS with a code of SYS_SECCOMP and related sigsys info. | ||
343 | */ | ||
344 | static void seccomp_send_sigsys(int syscall, int reason) | ||
345 | { | ||
346 | struct siginfo info; | ||
347 | memset(&info, 0, sizeof(info)); | ||
348 | info.si_signo = SIGSYS; | ||
349 | info.si_code = SYS_SECCOMP; | ||
350 | info.si_call_addr = (void __user *)KSTK_EIP(current); | ||
351 | info.si_errno = reason; | ||
352 | info.si_arch = syscall_get_arch(current, task_pt_regs(current)); | ||
353 | info.si_syscall = syscall; | ||
354 | force_sig_info(SIGSYS, &info, current); | ||
355 | } | ||
356 | #endif /* CONFIG_SECCOMP_FILTER */ | ||
16 | 357 | ||
17 | /* | 358 | /* |
18 | * Secure computing mode 1 allows only read/write/exit/sigreturn. | 359 | * Secure computing mode 1 allows only read/write/exit/sigreturn. |
@@ -31,13 +372,15 @@ static int mode1_syscalls_32[] = { | |||
31 | }; | 372 | }; |
32 | #endif | 373 | #endif |
33 | 374 | ||
34 | void __secure_computing(int this_syscall) | 375 | int __secure_computing(int this_syscall) |
35 | { | 376 | { |
36 | int mode = current->seccomp.mode; | 377 | int mode = current->seccomp.mode; |
37 | int * syscall; | 378 | int exit_sig = 0; |
379 | int *syscall; | ||
380 | u32 ret; | ||
38 | 381 | ||
39 | switch (mode) { | 382 | switch (mode) { |
40 | case 1: | 383 | case SECCOMP_MODE_STRICT: |
41 | syscall = mode1_syscalls; | 384 | syscall = mode1_syscalls; |
42 | #ifdef CONFIG_COMPAT | 385 | #ifdef CONFIG_COMPAT |
43 | if (is_compat_task()) | 386 | if (is_compat_task()) |
@@ -45,9 +388,54 @@ void __secure_computing(int this_syscall) | |||
45 | #endif | 388 | #endif |
46 | do { | 389 | do { |
47 | if (*syscall == this_syscall) | 390 | if (*syscall == this_syscall) |
48 | return; | 391 | return 0; |
49 | } while (*++syscall); | 392 | } while (*++syscall); |
393 | exit_sig = SIGKILL; | ||
394 | ret = SECCOMP_RET_KILL; | ||
395 | break; | ||
396 | #ifdef CONFIG_SECCOMP_FILTER | ||
397 | case SECCOMP_MODE_FILTER: { | ||
398 | int data; | ||
399 | ret = seccomp_run_filters(this_syscall); | ||
400 | data = ret & SECCOMP_RET_DATA; | ||
401 | ret &= SECCOMP_RET_ACTION; | ||
402 | switch (ret) { | ||
403 | case SECCOMP_RET_ERRNO: | ||
404 | /* Set the low-order 16-bits as a errno. */ | ||
405 | syscall_set_return_value(current, task_pt_regs(current), | ||
406 | -data, 0); | ||
407 | goto skip; | ||
408 | case SECCOMP_RET_TRAP: | ||
409 | /* Show the handler the original registers. */ | ||
410 | syscall_rollback(current, task_pt_regs(current)); | ||
411 | /* Let the filter pass back 16 bits of data. */ | ||
412 | seccomp_send_sigsys(this_syscall, data); | ||
413 | goto skip; | ||
414 | case SECCOMP_RET_TRACE: | ||
415 | /* Skip these calls if there is no tracer. */ | ||
416 | if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) | ||
417 | goto skip; | ||
418 | /* Allow the BPF to provide the event message */ | ||
419 | ptrace_event(PTRACE_EVENT_SECCOMP, data); | ||
420 | /* | ||
421 | * The delivery of a fatal signal during event | ||
422 | * notification may silently skip tracer notification. | ||
423 | * Terminating the task now avoids executing a system | ||
424 | * call that may not be intended. | ||
425 | */ | ||
426 | if (fatal_signal_pending(current)) | ||
427 | break; | ||
428 | return 0; | ||
429 | case SECCOMP_RET_ALLOW: | ||
430 | return 0; | ||
431 | case SECCOMP_RET_KILL: | ||
432 | default: | ||
433 | break; | ||
434 | } | ||
435 | exit_sig = SIGSYS; | ||
50 | break; | 436 | break; |
437 | } | ||
438 | #endif | ||
51 | default: | 439 | default: |
52 | BUG(); | 440 | BUG(); |
53 | } | 441 | } |
@@ -55,8 +443,13 @@ void __secure_computing(int this_syscall) | |||
55 | #ifdef SECCOMP_DEBUG | 443 | #ifdef SECCOMP_DEBUG |
56 | dump_stack(); | 444 | dump_stack(); |
57 | #endif | 445 | #endif |
58 | audit_seccomp(this_syscall); | 446 | audit_seccomp(this_syscall, exit_sig, ret); |
59 | do_exit(SIGKILL); | 447 | do_exit(exit_sig); |
448 | #ifdef CONFIG_SECCOMP_FILTER | ||
449 | skip: | ||
450 | audit_seccomp(this_syscall, exit_sig, ret); | ||
451 | #endif | ||
452 | return -1; | ||
60 | } | 453 | } |
61 | 454 | ||
62 | long prctl_get_seccomp(void) | 455 | long prctl_get_seccomp(void) |
@@ -64,25 +457,48 @@ long prctl_get_seccomp(void) | |||
64 | return current->seccomp.mode; | 457 | return current->seccomp.mode; |
65 | } | 458 | } |
66 | 459 | ||
67 | long prctl_set_seccomp(unsigned long seccomp_mode) | 460 | /** |
461 | * prctl_set_seccomp: configures current->seccomp.mode | ||
462 | * @seccomp_mode: requested mode to use | ||
463 | * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER | ||
464 | * | ||
465 | * This function may be called repeatedly with a @seccomp_mode of | ||
466 | * SECCOMP_MODE_FILTER to install additional filters. Every filter | ||
467 | * successfully installed will be evaluated (in reverse order) for each system | ||
468 | * call the task makes. | ||
469 | * | ||
470 | * Once current->seccomp.mode is non-zero, it may not be changed. | ||
471 | * | ||
472 | * Returns 0 on success or -EINVAL on failure. | ||
473 | */ | ||
474 | long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) | ||
68 | { | 475 | { |
69 | long ret; | 476 | long ret = -EINVAL; |
70 | 477 | ||
71 | /* can set it only once to be even more secure */ | 478 | if (current->seccomp.mode && |
72 | ret = -EPERM; | 479 | current->seccomp.mode != seccomp_mode) |
73 | if (unlikely(current->seccomp.mode)) | ||
74 | goto out; | 480 | goto out; |
75 | 481 | ||
76 | ret = -EINVAL; | 482 | switch (seccomp_mode) { |
77 | if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) { | 483 | case SECCOMP_MODE_STRICT: |
78 | current->seccomp.mode = seccomp_mode; | 484 | ret = 0; |
79 | set_thread_flag(TIF_SECCOMP); | ||
80 | #ifdef TIF_NOTSC | 485 | #ifdef TIF_NOTSC |
81 | disable_TSC(); | 486 | disable_TSC(); |
82 | #endif | 487 | #endif |
83 | ret = 0; | 488 | break; |
489 | #ifdef CONFIG_SECCOMP_FILTER | ||
490 | case SECCOMP_MODE_FILTER: | ||
491 | ret = seccomp_attach_user_filter(filter); | ||
492 | if (ret) | ||
493 | goto out; | ||
494 | break; | ||
495 | #endif | ||
496 | default: | ||
497 | goto out; | ||
84 | } | 498 | } |
85 | 499 | ||
86 | out: | 500 | current->seccomp.mode = seccomp_mode; |
501 | set_thread_flag(TIF_SECCOMP); | ||
502 | out: | ||
87 | return ret; | 503 | return ret; |
88 | } | 504 | } |
diff --git a/kernel/signal.c b/kernel/signal.c index 17afcaf582d0..1a006b5d9d9d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -160,7 +160,7 @@ void recalc_sigpending(void) | |||
160 | 160 | ||
161 | #define SYNCHRONOUS_MASK \ | 161 | #define SYNCHRONOUS_MASK \ |
162 | (sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \ | 162 | (sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \ |
163 | sigmask(SIGTRAP) | sigmask(SIGFPE)) | 163 | sigmask(SIGTRAP) | sigmask(SIGFPE) | sigmask(SIGSYS)) |
164 | 164 | ||
165 | int next_signal(struct sigpending *pending, sigset_t *mask) | 165 | int next_signal(struct sigpending *pending, sigset_t *mask) |
166 | { | 166 | { |
@@ -2706,6 +2706,13 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from) | |||
2706 | err |= __put_user(from->si_uid, &to->si_uid); | 2706 | err |= __put_user(from->si_uid, &to->si_uid); |
2707 | err |= __put_user(from->si_ptr, &to->si_ptr); | 2707 | err |= __put_user(from->si_ptr, &to->si_ptr); |
2708 | break; | 2708 | break; |
2709 | #ifdef __ARCH_SIGSYS | ||
2710 | case __SI_SYS: | ||
2711 | err |= __put_user(from->si_call_addr, &to->si_call_addr); | ||
2712 | err |= __put_user(from->si_syscall, &to->si_syscall); | ||
2713 | err |= __put_user(from->si_arch, &to->si_arch); | ||
2714 | break; | ||
2715 | #endif | ||
2709 | default: /* this is just in case for now ... */ | 2716 | default: /* this is just in case for now ... */ |
2710 | err |= __put_user(from->si_pid, &to->si_pid); | 2717 | err |= __put_user(from->si_pid, &to->si_pid); |
2711 | err |= __put_user(from->si_uid, &to->si_uid); | 2718 | err |= __put_user(from->si_uid, &to->si_uid); |
diff --git a/kernel/sys.c b/kernel/sys.c index e7006eb6c1e4..ba0ae8eea6fb 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1908,7 +1908,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1908 | error = prctl_get_seccomp(); | 1908 | error = prctl_get_seccomp(); |
1909 | break; | 1909 | break; |
1910 | case PR_SET_SECCOMP: | 1910 | case PR_SET_SECCOMP: |
1911 | error = prctl_set_seccomp(arg2); | 1911 | error = prctl_set_seccomp(arg2, (char __user *)arg3); |
1912 | break; | 1912 | break; |
1913 | case PR_GET_TSC: | 1913 | case PR_GET_TSC: |
1914 | error = GET_TSC_CTL(arg2); | 1914 | error = GET_TSC_CTL(arg2); |
@@ -1979,6 +1979,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1979 | error = put_user(me->signal->is_child_subreaper, | 1979 | error = put_user(me->signal->is_child_subreaper, |
1980 | (int __user *) arg2); | 1980 | (int __user *) arg2); |
1981 | break; | 1981 | break; |
1982 | case PR_SET_NO_NEW_PRIVS: | ||
1983 | if (arg2 != 1 || arg3 || arg4 || arg5) | ||
1984 | return -EINVAL; | ||
1985 | |||
1986 | current->no_new_privs = 1; | ||
1987 | break; | ||
1988 | case PR_GET_NO_NEW_PRIVS: | ||
1989 | if (arg2 || arg3 || arg4 || arg5) | ||
1990 | return -EINVAL; | ||
1991 | return current->no_new_privs ? 1 : 0; | ||
1982 | default: | 1992 | default: |
1983 | error = -EINVAL; | 1993 | error = -EINVAL; |
1984 | break; | 1994 | break; |
diff --git a/net/compat.c b/net/compat.c index e240441a2317..1b96281892de 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -328,14 +328,6 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) | |||
328 | __scm_destroy(scm); | 328 | __scm_destroy(scm); |
329 | } | 329 | } |
330 | 330 | ||
331 | /* | ||
332 | * A struct sock_filter is architecture independent. | ||
333 | */ | ||
334 | struct compat_sock_fprog { | ||
335 | u16 len; | ||
336 | compat_uptr_t filter; /* struct sock_filter * */ | ||
337 | }; | ||
338 | |||
339 | static int do_set_attach_filter(struct socket *sock, int level, int optname, | 331 | static int do_set_attach_filter(struct socket *sock, int level, int optname, |
340 | char __user *optval, unsigned int optlen) | 332 | char __user *optval, unsigned int optlen) |
341 | { | 333 | { |
diff --git a/net/core/filter.c b/net/core/filter.c index 47a5f055e7f3..a3eddb515d1b 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/filter.h> | 38 | #include <linux/filter.h> |
39 | #include <linux/reciprocal_div.h> | 39 | #include <linux/reciprocal_div.h> |
40 | #include <linux/ratelimit.h> | 40 | #include <linux/ratelimit.h> |
41 | #include <linux/seccomp.h> | ||
41 | 42 | ||
42 | /* No hurry in this branch | 43 | /* No hurry in this branch |
43 | * | 44 | * |
@@ -355,6 +356,11 @@ load_b: | |||
355 | A = 0; | 356 | A = 0; |
356 | continue; | 357 | continue; |
357 | } | 358 | } |
359 | #ifdef CONFIG_SECCOMP_FILTER | ||
360 | case BPF_S_ANC_SECCOMP_LD_W: | ||
361 | A = seccomp_bpf_load(fentry->k); | ||
362 | continue; | ||
363 | #endif | ||
358 | default: | 364 | default: |
359 | WARN_RATELIMIT(1, "Unknown code:%u jt:%u tf:%u k:%u\n", | 365 | WARN_RATELIMIT(1, "Unknown code:%u jt:%u tf:%u k:%u\n", |
360 | fentry->code, fentry->jt, | 366 | fentry->code, fentry->jt, |
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index 6f70ea935b0b..d9507dd05818 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c | |||
@@ -249,9 +249,6 @@ static int __init init_dns_resolver(void) | |||
249 | struct key *keyring; | 249 | struct key *keyring; |
250 | int ret; | 250 | int ret; |
251 | 251 | ||
252 | printk(KERN_NOTICE "Registering the %s key type\n", | ||
253 | key_type_dns_resolver.name); | ||
254 | |||
255 | /* create an override credential set with a special thread keyring in | 252 | /* create an override credential set with a special thread keyring in |
256 | * which DNS requests are cached | 253 | * which DNS requests are cached |
257 | * | 254 | * |
@@ -301,8 +298,6 @@ static void __exit exit_dns_resolver(void) | |||
301 | key_revoke(dns_resolver_cache->thread_keyring); | 298 | key_revoke(dns_resolver_cache->thread_keyring); |
302 | unregister_key_type(&key_type_dns_resolver); | 299 | unregister_key_type(&key_type_dns_resolver); |
303 | put_cred(dns_resolver_cache); | 300 | put_cred(dns_resolver_cache); |
304 | printk(KERN_NOTICE "Unregistered %s key type\n", | ||
305 | key_type_dns_resolver.name); | ||
306 | } | 301 | } |
307 | 302 | ||
308 | module_init(init_dns_resolver) | 303 | module_init(init_dns_resolver) |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 3c87a1c4066f..c53e8f42aa75 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/cache.h> | 26 | #include <linux/cache.h> |
27 | #include <linux/audit.h> | 27 | #include <linux/audit.h> |
28 | #include <net/dst.h> | 28 | #include <net/dst.h> |
29 | #include <net/flow.h> | ||
29 | #include <net/xfrm.h> | 30 | #include <net/xfrm.h> |
30 | #include <net/ip.h> | 31 | #include <net/ip.h> |
31 | #ifdef CONFIG_XFRM_STATISTICS | 32 | #ifdef CONFIG_XFRM_STATISTICS |
diff --git a/samples/Makefile b/samples/Makefile index 2f75851ec629..5ef08bba96ce 100644 --- a/samples/Makefile +++ b/samples/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | # Makefile for Linux samples code | 1 | # Makefile for Linux samples code |
2 | 2 | ||
3 | obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ tracepoints/ trace_events/ \ | 3 | obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ tracepoints/ trace_events/ \ |
4 | hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ | 4 | hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ |
diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile new file mode 100644 index 000000000000..16aa2d424985 --- /dev/null +++ b/samples/seccomp/Makefile | |||
@@ -0,0 +1,32 @@ | |||
1 | # kbuild trick to avoid linker error. Can be omitted if a module is built. | ||
2 | obj- := dummy.o | ||
3 | |||
4 | hostprogs-$(CONFIG_SECCOMP_FILTER) := bpf-fancy dropper bpf-direct | ||
5 | |||
6 | HOSTCFLAGS_bpf-fancy.o += -I$(objtree)/usr/include | ||
7 | HOSTCFLAGS_bpf-fancy.o += -idirafter $(objtree)/include | ||
8 | HOSTCFLAGS_bpf-helper.o += -I$(objtree)/usr/include | ||
9 | HOSTCFLAGS_bpf-helper.o += -idirafter $(objtree)/include | ||
10 | bpf-fancy-objs := bpf-fancy.o bpf-helper.o | ||
11 | |||
12 | HOSTCFLAGS_dropper.o += -I$(objtree)/usr/include | ||
13 | HOSTCFLAGS_dropper.o += -idirafter $(objtree)/include | ||
14 | dropper-objs := dropper.o | ||
15 | |||
16 | HOSTCFLAGS_bpf-direct.o += -I$(objtree)/usr/include | ||
17 | HOSTCFLAGS_bpf-direct.o += -idirafter $(objtree)/include | ||
18 | bpf-direct-objs := bpf-direct.o | ||
19 | |||
20 | # Try to match the kernel target. | ||
21 | ifeq ($(CONFIG_64BIT),) | ||
22 | HOSTCFLAGS_bpf-direct.o += -m32 | ||
23 | HOSTCFLAGS_dropper.o += -m32 | ||
24 | HOSTCFLAGS_bpf-helper.o += -m32 | ||
25 | HOSTCFLAGS_bpf-fancy.o += -m32 | ||
26 | HOSTLOADLIBES_bpf-direct += -m32 | ||
27 | HOSTLOADLIBES_bpf-fancy += -m32 | ||
28 | HOSTLOADLIBES_dropper += -m32 | ||
29 | endif | ||
30 | |||
31 | # Tell kbuild to always build the programs | ||
32 | always := $(hostprogs-y) | ||
diff --git a/samples/seccomp/bpf-direct.c b/samples/seccomp/bpf-direct.c new file mode 100644 index 000000000000..151ec3f52189 --- /dev/null +++ b/samples/seccomp/bpf-direct.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * Seccomp filter example for x86 (32-bit and 64-bit) with BPF macros | ||
3 | * | ||
4 | * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org> | ||
5 | * Author: Will Drewry <wad@chromium.org> | ||
6 | * | ||
7 | * The code may be used by anyone for any purpose, | ||
8 | * and can serve as a starting point for developing | ||
9 | * applications using prctl(PR_SET_SECCOMP, 2, ...). | ||
10 | */ | ||
11 | #if defined(__i386__) || defined(__x86_64__) | ||
12 | #define SUPPORTED_ARCH 1 | ||
13 | #endif | ||
14 | |||
15 | #if defined(SUPPORTED_ARCH) | ||
16 | #define __USE_GNU 1 | ||
17 | #define _GNU_SOURCE 1 | ||
18 | |||
19 | #include <linux/types.h> | ||
20 | #include <linux/filter.h> | ||
21 | #include <linux/seccomp.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <signal.h> | ||
24 | #include <stdio.h> | ||
25 | #include <stddef.h> | ||
26 | #include <string.h> | ||
27 | #include <sys/prctl.h> | ||
28 | #include <unistd.h> | ||
29 | |||
30 | #define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n])) | ||
31 | #define syscall_nr (offsetof(struct seccomp_data, nr)) | ||
32 | |||
33 | #if defined(__i386__) | ||
34 | #define REG_RESULT REG_EAX | ||
35 | #define REG_SYSCALL REG_EAX | ||
36 | #define REG_ARG0 REG_EBX | ||
37 | #define REG_ARG1 REG_ECX | ||
38 | #define REG_ARG2 REG_EDX | ||
39 | #define REG_ARG3 REG_ESI | ||
40 | #define REG_ARG4 REG_EDI | ||
41 | #define REG_ARG5 REG_EBP | ||
42 | #elif defined(__x86_64__) | ||
43 | #define REG_RESULT REG_RAX | ||
44 | #define REG_SYSCALL REG_RAX | ||
45 | #define REG_ARG0 REG_RDI | ||
46 | #define REG_ARG1 REG_RSI | ||
47 | #define REG_ARG2 REG_RDX | ||
48 | #define REG_ARG3 REG_R10 | ||
49 | #define REG_ARG4 REG_R8 | ||
50 | #define REG_ARG5 REG_R9 | ||
51 | #endif | ||
52 | |||
53 | #ifndef PR_SET_NO_NEW_PRIVS | ||
54 | #define PR_SET_NO_NEW_PRIVS 38 | ||
55 | #endif | ||
56 | |||
57 | #ifndef SYS_SECCOMP | ||
58 | #define SYS_SECCOMP 1 | ||
59 | #endif | ||
60 | |||
61 | static void emulator(int nr, siginfo_t *info, void *void_context) | ||
62 | { | ||
63 | ucontext_t *ctx = (ucontext_t *)(void_context); | ||
64 | int syscall; | ||
65 | char *buf; | ||
66 | ssize_t bytes; | ||
67 | size_t len; | ||
68 | if (info->si_code != SYS_SECCOMP) | ||
69 | return; | ||
70 | if (!ctx) | ||
71 | return; | ||
72 | syscall = ctx->uc_mcontext.gregs[REG_SYSCALL]; | ||
73 | buf = (char *) ctx->uc_mcontext.gregs[REG_ARG1]; | ||
74 | len = (size_t) ctx->uc_mcontext.gregs[REG_ARG2]; | ||
75 | |||
76 | if (syscall != __NR_write) | ||
77 | return; | ||
78 | if (ctx->uc_mcontext.gregs[REG_ARG0] != STDERR_FILENO) | ||
79 | return; | ||
80 | /* Redirect stderr messages to stdout. Doesn't handle EINTR, etc */ | ||
81 | ctx->uc_mcontext.gregs[REG_RESULT] = -1; | ||
82 | if (write(STDOUT_FILENO, "[ERR] ", 6) > 0) { | ||
83 | bytes = write(STDOUT_FILENO, buf, len); | ||
84 | ctx->uc_mcontext.gregs[REG_RESULT] = bytes; | ||
85 | } | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | static int install_emulator(void) | ||
90 | { | ||
91 | struct sigaction act; | ||
92 | sigset_t mask; | ||
93 | memset(&act, 0, sizeof(act)); | ||
94 | sigemptyset(&mask); | ||
95 | sigaddset(&mask, SIGSYS); | ||
96 | |||
97 | act.sa_sigaction = &emulator; | ||
98 | act.sa_flags = SA_SIGINFO; | ||
99 | if (sigaction(SIGSYS, &act, NULL) < 0) { | ||
100 | perror("sigaction"); | ||
101 | return -1; | ||
102 | } | ||
103 | if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) { | ||
104 | perror("sigprocmask"); | ||
105 | return -1; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int install_filter(void) | ||
111 | { | ||
112 | struct sock_filter filter[] = { | ||
113 | /* Grab the system call number */ | ||
114 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr), | ||
115 | /* Jump table for the allowed syscalls */ | ||
116 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_rt_sigreturn, 0, 1), | ||
117 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), | ||
118 | #ifdef __NR_sigreturn | ||
119 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_sigreturn, 0, 1), | ||
120 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), | ||
121 | #endif | ||
122 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit_group, 0, 1), | ||
123 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), | ||
124 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_exit, 0, 1), | ||
125 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), | ||
126 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_read, 1, 0), | ||
127 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_write, 3, 2), | ||
128 | |||
129 | /* Check that read is only using stdin. */ | ||
130 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)), | ||
131 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDIN_FILENO, 4, 0), | ||
132 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), | ||
133 | |||
134 | /* Check that write is only using stdout */ | ||
135 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_arg(0)), | ||
136 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDOUT_FILENO, 1, 0), | ||
137 | /* Trap attempts to write to stderr */ | ||
138 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, STDERR_FILENO, 1, 2), | ||
139 | |||
140 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), | ||
141 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP), | ||
142 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), | ||
143 | }; | ||
144 | struct sock_fprog prog = { | ||
145 | .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), | ||
146 | .filter = filter, | ||
147 | }; | ||
148 | |||
149 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
150 | perror("prctl(NO_NEW_PRIVS)"); | ||
151 | return 1; | ||
152 | } | ||
153 | |||
154 | |||
155 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { | ||
156 | perror("prctl"); | ||
157 | return 1; | ||
158 | } | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | #define payload(_c) (_c), sizeof((_c)) | ||
163 | int main(int argc, char **argv) | ||
164 | { | ||
165 | char buf[4096]; | ||
166 | ssize_t bytes = 0; | ||
167 | if (install_emulator()) | ||
168 | return 1; | ||
169 | if (install_filter()) | ||
170 | return 1; | ||
171 | syscall(__NR_write, STDOUT_FILENO, | ||
172 | payload("OHAI! WHAT IS YOUR NAME? ")); | ||
173 | bytes = syscall(__NR_read, STDIN_FILENO, buf, sizeof(buf)); | ||
174 | syscall(__NR_write, STDOUT_FILENO, payload("HELLO, ")); | ||
175 | syscall(__NR_write, STDOUT_FILENO, buf, bytes); | ||
176 | syscall(__NR_write, STDERR_FILENO, | ||
177 | payload("Error message going to STDERR\n")); | ||
178 | return 0; | ||
179 | } | ||
180 | #else /* SUPPORTED_ARCH */ | ||
181 | /* | ||
182 | * This sample is x86-only. Since kernel samples are compiled with the | ||
183 | * host toolchain, a non-x86 host will result in using only the main() | ||
184 | * below. | ||
185 | */ | ||
186 | int main(void) | ||
187 | { | ||
188 | return 1; | ||
189 | } | ||
190 | #endif /* SUPPORTED_ARCH */ | ||
diff --git a/samples/seccomp/bpf-fancy.c b/samples/seccomp/bpf-fancy.c new file mode 100644 index 000000000000..8eb483aaec46 --- /dev/null +++ b/samples/seccomp/bpf-fancy.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * Seccomp BPF example using a macro-based generator. | ||
3 | * | ||
4 | * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org> | ||
5 | * Author: Will Drewry <wad@chromium.org> | ||
6 | * | ||
7 | * The code may be used by anyone for any purpose, | ||
8 | * and can serve as a starting point for developing | ||
9 | * applications using prctl(PR_ATTACH_SECCOMP_FILTER). | ||
10 | */ | ||
11 | |||
12 | #include <linux/filter.h> | ||
13 | #include <linux/seccomp.h> | ||
14 | #include <linux/unistd.h> | ||
15 | #include <stdio.h> | ||
16 | #include <string.h> | ||
17 | #include <sys/prctl.h> | ||
18 | #include <unistd.h> | ||
19 | |||
20 | #include "bpf-helper.h" | ||
21 | |||
22 | #ifndef PR_SET_NO_NEW_PRIVS | ||
23 | #define PR_SET_NO_NEW_PRIVS 38 | ||
24 | #endif | ||
25 | |||
26 | int main(int argc, char **argv) | ||
27 | { | ||
28 | struct bpf_labels l; | ||
29 | static const char msg1[] = "Please type something: "; | ||
30 | static const char msg2[] = "You typed: "; | ||
31 | char buf[256]; | ||
32 | struct sock_filter filter[] = { | ||
33 | /* TODO: LOAD_SYSCALL_NR(arch) and enforce an arch */ | ||
34 | LOAD_SYSCALL_NR, | ||
35 | SYSCALL(__NR_exit, ALLOW), | ||
36 | SYSCALL(__NR_exit_group, ALLOW), | ||
37 | SYSCALL(__NR_write, JUMP(&l, write_fd)), | ||
38 | SYSCALL(__NR_read, JUMP(&l, read)), | ||
39 | DENY, /* Don't passthrough into a label */ | ||
40 | |||
41 | LABEL(&l, read), | ||
42 | ARG(0), | ||
43 | JNE(STDIN_FILENO, DENY), | ||
44 | ARG(1), | ||
45 | JNE((unsigned long)buf, DENY), | ||
46 | ARG(2), | ||
47 | JGE(sizeof(buf), DENY), | ||
48 | ALLOW, | ||
49 | |||
50 | LABEL(&l, write_fd), | ||
51 | ARG(0), | ||
52 | JEQ(STDOUT_FILENO, JUMP(&l, write_buf)), | ||
53 | JEQ(STDERR_FILENO, JUMP(&l, write_buf)), | ||
54 | DENY, | ||
55 | |||
56 | LABEL(&l, write_buf), | ||
57 | ARG(1), | ||
58 | JEQ((unsigned long)msg1, JUMP(&l, msg1_len)), | ||
59 | JEQ((unsigned long)msg2, JUMP(&l, msg2_len)), | ||
60 | JEQ((unsigned long)buf, JUMP(&l, buf_len)), | ||
61 | DENY, | ||
62 | |||
63 | LABEL(&l, msg1_len), | ||
64 | ARG(2), | ||
65 | JLT(sizeof(msg1), ALLOW), | ||
66 | DENY, | ||
67 | |||
68 | LABEL(&l, msg2_len), | ||
69 | ARG(2), | ||
70 | JLT(sizeof(msg2), ALLOW), | ||
71 | DENY, | ||
72 | |||
73 | LABEL(&l, buf_len), | ||
74 | ARG(2), | ||
75 | JLT(sizeof(buf), ALLOW), | ||
76 | DENY, | ||
77 | }; | ||
78 | struct sock_fprog prog = { | ||
79 | .filter = filter, | ||
80 | .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), | ||
81 | }; | ||
82 | ssize_t bytes; | ||
83 | bpf_resolve_jumps(&l, filter, sizeof(filter)/sizeof(*filter)); | ||
84 | |||
85 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
86 | perror("prctl(NO_NEW_PRIVS)"); | ||
87 | return 1; | ||
88 | } | ||
89 | |||
90 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { | ||
91 | perror("prctl(SECCOMP)"); | ||
92 | return 1; | ||
93 | } | ||
94 | syscall(__NR_write, STDOUT_FILENO, msg1, strlen(msg1)); | ||
95 | bytes = syscall(__NR_read, STDIN_FILENO, buf, sizeof(buf)-1); | ||
96 | bytes = (bytes > 0 ? bytes : 0); | ||
97 | syscall(__NR_write, STDERR_FILENO, msg2, strlen(msg2)); | ||
98 | syscall(__NR_write, STDERR_FILENO, buf, bytes); | ||
99 | /* Now get killed */ | ||
100 | syscall(__NR_write, STDERR_FILENO, msg2, strlen(msg2)+2); | ||
101 | return 0; | ||
102 | } | ||
diff --git a/samples/seccomp/bpf-helper.c b/samples/seccomp/bpf-helper.c new file mode 100644 index 000000000000..579cfe331886 --- /dev/null +++ b/samples/seccomp/bpf-helper.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * Seccomp BPF helper functions | ||
3 | * | ||
4 | * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org> | ||
5 | * Author: Will Drewry <wad@chromium.org> | ||
6 | * | ||
7 | * The code may be used by anyone for any purpose, | ||
8 | * and can serve as a starting point for developing | ||
9 | * applications using prctl(PR_ATTACH_SECCOMP_FILTER). | ||
10 | */ | ||
11 | |||
12 | #include <stdio.h> | ||
13 | #include <string.h> | ||
14 | |||
15 | #include "bpf-helper.h" | ||
16 | |||
17 | int bpf_resolve_jumps(struct bpf_labels *labels, | ||
18 | struct sock_filter *filter, size_t count) | ||
19 | { | ||
20 | struct sock_filter *begin = filter; | ||
21 | __u8 insn = count - 1; | ||
22 | |||
23 | if (count < 1) | ||
24 | return -1; | ||
25 | /* | ||
26 | * Walk it once, backwards, to build the label table and do fixups. | ||
27 | * Since backward jumps are disallowed by BPF, this is easy. | ||
28 | */ | ||
29 | filter += insn; | ||
30 | for (; filter >= begin; --insn, --filter) { | ||
31 | if (filter->code != (BPF_JMP+BPF_JA)) | ||
32 | continue; | ||
33 | switch ((filter->jt<<8)|filter->jf) { | ||
34 | case (JUMP_JT<<8)|JUMP_JF: | ||
35 | if (labels->labels[filter->k].location == 0xffffffff) { | ||
36 | fprintf(stderr, "Unresolved label: '%s'\n", | ||
37 | labels->labels[filter->k].label); | ||
38 | return 1; | ||
39 | } | ||
40 | filter->k = labels->labels[filter->k].location - | ||
41 | (insn + 1); | ||
42 | filter->jt = 0; | ||
43 | filter->jf = 0; | ||
44 | continue; | ||
45 | case (LABEL_JT<<8)|LABEL_JF: | ||
46 | if (labels->labels[filter->k].location != 0xffffffff) { | ||
47 | fprintf(stderr, "Duplicate label use: '%s'\n", | ||
48 | labels->labels[filter->k].label); | ||
49 | return 1; | ||
50 | } | ||
51 | labels->labels[filter->k].location = insn; | ||
52 | filter->k = 0; /* fall through */ | ||
53 | filter->jt = 0; | ||
54 | filter->jf = 0; | ||
55 | continue; | ||
56 | } | ||
57 | } | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | /* Simple lookup table for labels. */ | ||
62 | __u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label) | ||
63 | { | ||
64 | struct __bpf_label *begin = labels->labels, *end; | ||
65 | int id; | ||
66 | if (labels->count == 0) { | ||
67 | begin->label = label; | ||
68 | begin->location = 0xffffffff; | ||
69 | labels->count++; | ||
70 | return 0; | ||
71 | } | ||
72 | end = begin + labels->count; | ||
73 | for (id = 0; begin < end; ++begin, ++id) { | ||
74 | if (!strcmp(label, begin->label)) | ||
75 | return id; | ||
76 | } | ||
77 | begin->label = label; | ||
78 | begin->location = 0xffffffff; | ||
79 | labels->count++; | ||
80 | return id; | ||
81 | } | ||
82 | |||
83 | void seccomp_bpf_print(struct sock_filter *filter, size_t count) | ||
84 | { | ||
85 | struct sock_filter *end = filter + count; | ||
86 | for ( ; filter < end; ++filter) | ||
87 | printf("{ code=%u,jt=%u,jf=%u,k=%u },\n", | ||
88 | filter->code, filter->jt, filter->jf, filter->k); | ||
89 | } | ||
diff --git a/samples/seccomp/bpf-helper.h b/samples/seccomp/bpf-helper.h new file mode 100644 index 000000000000..643279dd30fb --- /dev/null +++ b/samples/seccomp/bpf-helper.h | |||
@@ -0,0 +1,238 @@ | |||
1 | /* | ||
2 | * Example wrapper around BPF macros. | ||
3 | * | ||
4 | * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org> | ||
5 | * Author: Will Drewry <wad@chromium.org> | ||
6 | * | ||
7 | * The code may be used by anyone for any purpose, | ||
8 | * and can serve as a starting point for developing | ||
9 | * applications using prctl(PR_SET_SECCOMP, 2, ...). | ||
10 | * | ||
11 | * No guarantees are provided with respect to the correctness | ||
12 | * or functionality of this code. | ||
13 | */ | ||
14 | #ifndef __BPF_HELPER_H__ | ||
15 | #define __BPF_HELPER_H__ | ||
16 | |||
17 | #include <asm/bitsperlong.h> /* for __BITS_PER_LONG */ | ||
18 | #include <endian.h> | ||
19 | #include <linux/filter.h> | ||
20 | #include <linux/seccomp.h> /* for seccomp_data */ | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <stddef.h> | ||
24 | |||
25 | #define BPF_LABELS_MAX 256 | ||
26 | struct bpf_labels { | ||
27 | int count; | ||
28 | struct __bpf_label { | ||
29 | const char *label; | ||
30 | __u32 location; | ||
31 | } labels[BPF_LABELS_MAX]; | ||
32 | }; | ||
33 | |||
34 | int bpf_resolve_jumps(struct bpf_labels *labels, | ||
35 | struct sock_filter *filter, size_t count); | ||
36 | __u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label); | ||
37 | void seccomp_bpf_print(struct sock_filter *filter, size_t count); | ||
38 | |||
39 | #define JUMP_JT 0xff | ||
40 | #define JUMP_JF 0xff | ||
41 | #define LABEL_JT 0xfe | ||
42 | #define LABEL_JF 0xfe | ||
43 | |||
44 | #define ALLOW \ | ||
45 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) | ||
46 | #define DENY \ | ||
47 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) | ||
48 | #define JUMP(labels, label) \ | ||
49 | BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \ | ||
50 | JUMP_JT, JUMP_JF) | ||
51 | #define LABEL(labels, label) \ | ||
52 | BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \ | ||
53 | LABEL_JT, LABEL_JF) | ||
54 | #define SYSCALL(nr, jt) \ | ||
55 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (nr), 0, 1), \ | ||
56 | jt | ||
57 | |||
58 | /* Lame, but just an example */ | ||
59 | #define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label) | ||
60 | |||
61 | #define EXPAND(...) __VA_ARGS__ | ||
62 | /* Map all width-sensitive operations */ | ||
63 | #if __BITS_PER_LONG == 32 | ||
64 | |||
65 | #define JEQ(x, jt) JEQ32(x, EXPAND(jt)) | ||
66 | #define JNE(x, jt) JNE32(x, EXPAND(jt)) | ||
67 | #define JGT(x, jt) JGT32(x, EXPAND(jt)) | ||
68 | #define JLT(x, jt) JLT32(x, EXPAND(jt)) | ||
69 | #define JGE(x, jt) JGE32(x, EXPAND(jt)) | ||
70 | #define JLE(x, jt) JLE32(x, EXPAND(jt)) | ||
71 | #define JA(x, jt) JA32(x, EXPAND(jt)) | ||
72 | #define ARG(i) ARG_32(i) | ||
73 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) | ||
74 | |||
75 | #elif __BITS_PER_LONG == 64 | ||
76 | |||
77 | /* Ensure that we load the logically correct offset. */ | ||
78 | #if __BYTE_ORDER == __LITTLE_ENDIAN | ||
79 | #define ENDIAN(_lo, _hi) _lo, _hi | ||
80 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) | ||
81 | #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) | ||
82 | #elif __BYTE_ORDER == __BIG_ENDIAN | ||
83 | #define ENDIAN(_lo, _hi) _hi, _lo | ||
84 | #define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) | ||
85 | #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) | ||
86 | #else | ||
87 | #error "Unknown endianness" | ||
88 | #endif | ||
89 | |||
90 | union arg64 { | ||
91 | struct { | ||
92 | __u32 ENDIAN(lo32, hi32); | ||
93 | }; | ||
94 | __u64 u64; | ||
95 | }; | ||
96 | |||
97 | #define JEQ(x, jt) \ | ||
98 | JEQ64(((union arg64){.u64 = (x)}).lo32, \ | ||
99 | ((union arg64){.u64 = (x)}).hi32, \ | ||
100 | EXPAND(jt)) | ||
101 | #define JGT(x, jt) \ | ||
102 | JGT64(((union arg64){.u64 = (x)}).lo32, \ | ||
103 | ((union arg64){.u64 = (x)}).hi32, \ | ||
104 | EXPAND(jt)) | ||
105 | #define JGE(x, jt) \ | ||
106 | JGE64(((union arg64){.u64 = (x)}).lo32, \ | ||
107 | ((union arg64){.u64 = (x)}).hi32, \ | ||
108 | EXPAND(jt)) | ||
109 | #define JNE(x, jt) \ | ||
110 | JNE64(((union arg64){.u64 = (x)}).lo32, \ | ||
111 | ((union arg64){.u64 = (x)}).hi32, \ | ||
112 | EXPAND(jt)) | ||
113 | #define JLT(x, jt) \ | ||
114 | JLT64(((union arg64){.u64 = (x)}).lo32, \ | ||
115 | ((union arg64){.u64 = (x)}).hi32, \ | ||
116 | EXPAND(jt)) | ||
117 | #define JLE(x, jt) \ | ||
118 | JLE64(((union arg64){.u64 = (x)}).lo32, \ | ||
119 | ((union arg64){.u64 = (x)}).hi32, \ | ||
120 | EXPAND(jt)) | ||
121 | |||
122 | #define JA(x, jt) \ | ||
123 | JA64(((union arg64){.u64 = (x)}).lo32, \ | ||
124 | ((union arg64){.u64 = (x)}).hi32, \ | ||
125 | EXPAND(jt)) | ||
126 | #define ARG(i) ARG_64(i) | ||
127 | |||
128 | #else | ||
129 | #error __BITS_PER_LONG value unusable. | ||
130 | #endif | ||
131 | |||
132 | /* Loads the arg into A */ | ||
133 | #define ARG_32(idx) \ | ||
134 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)) | ||
135 | |||
136 | /* Loads hi into A and lo in X */ | ||
137 | #define ARG_64(idx) \ | ||
138 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \ | ||
139 | BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \ | ||
140 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, HI_ARG(idx)), \ | ||
141 | BPF_STMT(BPF_ST, 1) /* hi -> M[1] */ | ||
142 | |||
143 | #define JEQ32(value, jt) \ | ||
144 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 0, 1), \ | ||
145 | jt | ||
146 | |||
147 | #define JNE32(value, jt) \ | ||
148 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \ | ||
149 | jt | ||
150 | |||
151 | /* Checks the lo, then swaps to check the hi. A=lo,X=hi */ | ||
152 | #define JEQ64(lo, hi, jt) \ | ||
153 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ | ||
154 | BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ | ||
155 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \ | ||
156 | BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ | ||
157 | jt, \ | ||
158 | BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ | ||
159 | |||
160 | #define JNE64(lo, hi, jt) \ | ||
161 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 5, 0), \ | ||
162 | BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ | ||
163 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \ | ||
164 | BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ | ||
165 | jt, \ | ||
166 | BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ | ||
167 | |||
168 | #define JA32(value, jt) \ | ||
169 | BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \ | ||
170 | jt | ||
171 | |||
172 | #define JA64(lo, hi, jt) \ | ||
173 | BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \ | ||
174 | BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ | ||
175 | BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \ | ||
176 | BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ | ||
177 | jt, \ | ||
178 | BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ | ||
179 | |||
180 | #define JGE32(value, jt) \ | ||
181 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \ | ||
182 | jt | ||
183 | |||
184 | #define JLT32(value, jt) \ | ||
185 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \ | ||
186 | jt | ||
187 | |||
188 | /* Shortcut checking if hi > arg.hi. */ | ||
189 | #define JGE64(lo, hi, jt) \ | ||
190 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ | ||
191 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ | ||
192 | BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ | ||
193 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \ | ||
194 | BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ | ||
195 | jt, \ | ||
196 | BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ | ||
197 | |||
198 | #define JLT64(lo, hi, jt) \ | ||
199 | BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ | ||
200 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ | ||
201 | BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ | ||
202 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \ | ||
203 | BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ | ||
204 | jt, \ | ||
205 | BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ | ||
206 | |||
207 | #define JGT32(value, jt) \ | ||
208 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \ | ||
209 | jt | ||
210 | |||
211 | #define JLE32(value, jt) \ | ||
212 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \ | ||
213 | jt | ||
214 | |||
215 | /* Check hi > args.hi first, then do the GE checking */ | ||
216 | #define JGT64(lo, hi, jt) \ | ||
217 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ | ||
218 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ | ||
219 | BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ | ||
220 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \ | ||
221 | BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ | ||
222 | jt, \ | ||
223 | BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ | ||
224 | |||
225 | #define JLE64(lo, hi, jt) \ | ||
226 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 6, 0), \ | ||
227 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \ | ||
228 | BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ | ||
229 | BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \ | ||
230 | BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \ | ||
231 | jt, \ | ||
232 | BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */ | ||
233 | |||
234 | #define LOAD_SYSCALL_NR \ | ||
235 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ | ||
236 | offsetof(struct seccomp_data, nr)) | ||
237 | |||
238 | #endif /* __BPF_HELPER_H__ */ | ||
diff --git a/samples/seccomp/dropper.c b/samples/seccomp/dropper.c new file mode 100644 index 000000000000..c69c347c7011 --- /dev/null +++ b/samples/seccomp/dropper.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Naive system call dropper built on seccomp_filter. | ||
3 | * | ||
4 | * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org> | ||
5 | * Author: Will Drewry <wad@chromium.org> | ||
6 | * | ||
7 | * The code may be used by anyone for any purpose, | ||
8 | * and can serve as a starting point for developing | ||
9 | * applications using prctl(PR_SET_SECCOMP, 2, ...). | ||
10 | * | ||
11 | * When run, returns the specified errno for the specified | ||
12 | * system call number against the given architecture. | ||
13 | * | ||
14 | * Run this one as root as PR_SET_NO_NEW_PRIVS is not called. | ||
15 | */ | ||
16 | |||
17 | #include <errno.h> | ||
18 | #include <linux/audit.h> | ||
19 | #include <linux/filter.h> | ||
20 | #include <linux/seccomp.h> | ||
21 | #include <linux/unistd.h> | ||
22 | #include <stdio.h> | ||
23 | #include <stddef.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <sys/prctl.h> | ||
26 | #include <unistd.h> | ||
27 | |||
28 | static int install_filter(int nr, int arch, int error) | ||
29 | { | ||
30 | struct sock_filter filter[] = { | ||
31 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, | ||
32 | (offsetof(struct seccomp_data, arch))), | ||
33 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, arch, 0, 3), | ||
34 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, | ||
35 | (offsetof(struct seccomp_data, nr))), | ||
36 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1), | ||
37 | BPF_STMT(BPF_RET+BPF_K, | ||
38 | SECCOMP_RET_ERRNO|(error & SECCOMP_RET_DATA)), | ||
39 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), | ||
40 | }; | ||
41 | struct sock_fprog prog = { | ||
42 | .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), | ||
43 | .filter = filter, | ||
44 | }; | ||
45 | if (prctl(PR_SET_SECCOMP, 2, &prog)) { | ||
46 | perror("prctl"); | ||
47 | return 1; | ||
48 | } | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | int main(int argc, char **argv) | ||
53 | { | ||
54 | if (argc < 5) { | ||
55 | fprintf(stderr, "Usage:\n" | ||
56 | "dropper <syscall_nr> <arch> <errno> <prog> [<args>]\n" | ||
57 | "Hint: AUDIT_ARCH_I386: 0x%X\n" | ||
58 | " AUDIT_ARCH_X86_64: 0x%X\n" | ||
59 | "\n", AUDIT_ARCH_I386, AUDIT_ARCH_X86_64); | ||
60 | return 1; | ||
61 | } | ||
62 | if (install_filter(strtol(argv[1], NULL, 0), strtol(argv[2], NULL, 0), | ||
63 | strtol(argv[3], NULL, 0))) | ||
64 | return 1; | ||
65 | execv(argv[4], &argv[4]); | ||
66 | printf("Failed to execv\n"); | ||
67 | return 255; | ||
68 | } | ||
diff --git a/security/Kconfig b/security/Kconfig index ccc61f8006b2..e9c6ac724fef 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -4,73 +4,7 @@ | |||
4 | 4 | ||
5 | menu "Security options" | 5 | menu "Security options" |
6 | 6 | ||
7 | config KEYS | 7 | source security/keys/Kconfig |
8 | bool "Enable access key retention support" | ||
9 | help | ||
10 | This option provides support for retaining authentication tokens and | ||
11 | access keys in the kernel. | ||
12 | |||
13 | It also includes provision of methods by which such keys might be | ||
14 | associated with a process so that network filesystems, encryption | ||
15 | support and the like can find them. | ||
16 | |||
17 | Furthermore, a special type of key is available that acts as keyring: | ||
18 | a searchable sequence of keys. Each process is equipped with access | ||
19 | to five standard keyrings: UID-specific, GID-specific, session, | ||
20 | process and thread. | ||
21 | |||
22 | If you are unsure as to whether this is required, answer N. | ||
23 | |||
24 | config TRUSTED_KEYS | ||
25 | tristate "TRUSTED KEYS" | ||
26 | depends on KEYS && TCG_TPM | ||
27 | select CRYPTO | ||
28 | select CRYPTO_HMAC | ||
29 | select CRYPTO_SHA1 | ||
30 | help | ||
31 | This option provides support for creating, sealing, and unsealing | ||
32 | keys in the kernel. Trusted keys are random number symmetric keys, | ||
33 | generated and RSA-sealed by the TPM. The TPM only unseals the keys, | ||
34 | if the boot PCRs and other criteria match. Userspace will only ever | ||
35 | see encrypted blobs. | ||
36 | |||
37 | If you are unsure as to whether this is required, answer N. | ||
38 | |||
39 | config ENCRYPTED_KEYS | ||
40 | tristate "ENCRYPTED KEYS" | ||
41 | depends on KEYS | ||
42 | select CRYPTO | ||
43 | select CRYPTO_HMAC | ||
44 | select CRYPTO_AES | ||
45 | select CRYPTO_CBC | ||
46 | select CRYPTO_SHA256 | ||
47 | select CRYPTO_RNG | ||
48 | help | ||
49 | This option provides support for create/encrypting/decrypting keys | ||
50 | in the kernel. Encrypted keys are kernel generated random numbers, | ||
51 | which are encrypted/decrypted with a 'master' symmetric key. The | ||
52 | 'master' key can be either a trusted-key or user-key type. | ||
53 | Userspace only ever sees/stores encrypted blobs. | ||
54 | |||
55 | If you are unsure as to whether this is required, answer N. | ||
56 | |||
57 | config KEYS_DEBUG_PROC_KEYS | ||
58 | bool "Enable the /proc/keys file by which keys may be viewed" | ||
59 | depends on KEYS | ||
60 | help | ||
61 | This option turns on support for the /proc/keys file - through which | ||
62 | can be listed all the keys on the system that are viewable by the | ||
63 | reading process. | ||
64 | |||
65 | The only keys included in the list are those that grant View | ||
66 | permission to the reading process whether or not it possesses them. | ||
67 | Note that LSM security checks are still performed, and may further | ||
68 | filter out keys that the current process is not authorised to view. | ||
69 | |||
70 | Only key attributes are listed here; key payloads are not included in | ||
71 | the resulting table. | ||
72 | |||
73 | If you are unsure as to whether this is required, answer N. | ||
74 | 8 | ||
75 | config SECURITY_DMESG_RESTRICT | 9 | config SECURITY_DMESG_RESTRICT |
76 | bool "Restrict unprivileged access to the kernel syslog" | 10 | bool "Restrict unprivileged access to the kernel syslog" |
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index cc3520d39a78..3ae28db5a64f 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c | |||
@@ -111,7 +111,7 @@ static const char *const aa_audit_type[] = { | |||
111 | static void audit_pre(struct audit_buffer *ab, void *ca) | 111 | static void audit_pre(struct audit_buffer *ab, void *ca) |
112 | { | 112 | { |
113 | struct common_audit_data *sa = ca; | 113 | struct common_audit_data *sa = ca; |
114 | struct task_struct *tsk = sa->tsk ? sa->tsk : current; | 114 | struct task_struct *tsk = sa->aad->tsk ? sa->aad->tsk : current; |
115 | 115 | ||
116 | if (aa_g_audit_header) { | 116 | if (aa_g_audit_header) { |
117 | audit_log_format(ab, "apparmor="); | 117 | audit_log_format(ab, "apparmor="); |
@@ -149,6 +149,12 @@ static void audit_pre(struct audit_buffer *ab, void *ca) | |||
149 | audit_log_format(ab, " name="); | 149 | audit_log_format(ab, " name="); |
150 | audit_log_untrustedstring(ab, sa->aad->name); | 150 | audit_log_untrustedstring(ab, sa->aad->name); |
151 | } | 151 | } |
152 | |||
153 | if (sa->aad->tsk) { | ||
154 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | ||
155 | audit_log_untrustedstring(ab, tsk->comm); | ||
156 | } | ||
157 | |||
152 | } | 158 | } |
153 | 159 | ||
154 | /** | 160 | /** |
@@ -205,7 +211,8 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, | |||
205 | aa_audit_msg(type, sa, cb); | 211 | aa_audit_msg(type, sa, cb); |
206 | 212 | ||
207 | if (sa->aad->type == AUDIT_APPARMOR_KILL) | 213 | if (sa->aad->type == AUDIT_APPARMOR_KILL) |
208 | (void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current); | 214 | (void)send_sig_info(SIGKILL, NULL, |
215 | sa->aad->tsk ? sa->aad->tsk : current); | ||
209 | 216 | ||
210 | if (sa->aad->type == AUDIT_APPARMOR_ALLOWED) | 217 | if (sa->aad->type == AUDIT_APPARMOR_ALLOWED) |
211 | return complain_error(sa->aad->error); | 218 | return complain_error(sa->aad->error); |
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 088dba3bf7dc..887a5e948945 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c | |||
@@ -65,10 +65,10 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task, | |||
65 | int type = AUDIT_APPARMOR_AUTO; | 65 | int type = AUDIT_APPARMOR_AUTO; |
66 | struct common_audit_data sa; | 66 | struct common_audit_data sa; |
67 | struct apparmor_audit_data aad = {0,}; | 67 | struct apparmor_audit_data aad = {0,}; |
68 | COMMON_AUDIT_DATA_INIT(&sa, CAP); | 68 | sa.type = LSM_AUDIT_DATA_CAP; |
69 | sa.aad = &aad; | 69 | sa.aad = &aad; |
70 | sa.tsk = task; | ||
71 | sa.u.cap = cap; | 70 | sa.u.cap = cap; |
71 | sa.aad->tsk = task; | ||
72 | sa.aad->op = OP_CAPABLE; | 72 | sa.aad->op = OP_CAPABLE; |
73 | sa.aad->error = error; | 73 | sa.aad->error = error; |
74 | 74 | ||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 6327685c101e..b81ea10a17a3 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
@@ -394,6 +394,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) | |||
394 | new_profile = find_attach(ns, &ns->base.profiles, name); | 394 | new_profile = find_attach(ns, &ns->base.profiles, name); |
395 | if (!new_profile) | 395 | if (!new_profile) |
396 | goto cleanup; | 396 | goto cleanup; |
397 | /* | ||
398 | * NOTE: Domain transitions from unconfined are allowed | ||
399 | * even when no_new_privs is set because this aways results | ||
400 | * in a further reduction of permissions. | ||
401 | */ | ||
397 | goto apply; | 402 | goto apply; |
398 | } | 403 | } |
399 | 404 | ||
@@ -455,6 +460,16 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) | |||
455 | /* fail exec */ | 460 | /* fail exec */ |
456 | error = -EACCES; | 461 | error = -EACCES; |
457 | 462 | ||
463 | /* | ||
464 | * Policy has specified a domain transition, if no_new_privs then | ||
465 | * fail the exec. | ||
466 | */ | ||
467 | if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) { | ||
468 | aa_put_profile(new_profile); | ||
469 | error = -EPERM; | ||
470 | goto cleanup; | ||
471 | } | ||
472 | |||
458 | if (!new_profile) | 473 | if (!new_profile) |
459 | goto audit; | 474 | goto audit; |
460 | 475 | ||
@@ -609,6 +624,14 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) | |||
609 | const char *target = NULL, *info = NULL; | 624 | const char *target = NULL, *info = NULL; |
610 | int error = 0; | 625 | int error = 0; |
611 | 626 | ||
627 | /* | ||
628 | * Fail explicitly requested domain transitions if no_new_privs. | ||
629 | * There is no exception for unconfined as change_hat is not | ||
630 | * available. | ||
631 | */ | ||
632 | if (current->no_new_privs) | ||
633 | return -EPERM; | ||
634 | |||
612 | /* released below */ | 635 | /* released below */ |
613 | cred = get_current_cred(); | 636 | cred = get_current_cred(); |
614 | cxt = cred->security; | 637 | cxt = cred->security; |
@@ -750,6 +773,18 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, | |||
750 | cxt = cred->security; | 773 | cxt = cred->security; |
751 | profile = aa_cred_profile(cred); | 774 | profile = aa_cred_profile(cred); |
752 | 775 | ||
776 | /* | ||
777 | * Fail explicitly requested domain transitions if no_new_privs | ||
778 | * and not unconfined. | ||
779 | * Domain transitions from unconfined are allowed even when | ||
780 | * no_new_privs is set because this aways results in a reduction | ||
781 | * of permissions. | ||
782 | */ | ||
783 | if (current->no_new_privs && !unconfined(profile)) { | ||
784 | put_cred(cred); | ||
785 | return -EPERM; | ||
786 | } | ||
787 | |||
753 | if (ns_name) { | 788 | if (ns_name) { |
754 | /* released below */ | 789 | /* released below */ |
755 | ns = aa_find_namespace(profile->ns, ns_name); | 790 | ns = aa_find_namespace(profile->ns, ns_name); |
diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 2f8fcba9ce4b..cf19d4093ca4 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c | |||
@@ -108,7 +108,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, | |||
108 | int type = AUDIT_APPARMOR_AUTO; | 108 | int type = AUDIT_APPARMOR_AUTO; |
109 | struct common_audit_data sa; | 109 | struct common_audit_data sa; |
110 | struct apparmor_audit_data aad = {0,}; | 110 | struct apparmor_audit_data aad = {0,}; |
111 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 111 | sa.type = LSM_AUDIT_DATA_NONE; |
112 | sa.aad = &aad; | 112 | sa.aad = &aad; |
113 | aad.op = op, | 113 | aad.op = op, |
114 | aad.fs.request = request; | 114 | aad.fs.request = request; |
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 3868b1e5d5ba..4b7e18951aea 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h | |||
@@ -110,6 +110,7 @@ struct apparmor_audit_data { | |||
110 | void *profile; | 110 | void *profile; |
111 | const char *name; | 111 | const char *name; |
112 | const char *info; | 112 | const char *info; |
113 | struct task_struct *tsk; | ||
113 | union { | 114 | union { |
114 | void *target; | 115 | void *target; |
115 | struct { | 116 | struct { |
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index c3da93a5150d..cf1071b14232 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c | |||
@@ -42,7 +42,7 @@ static int aa_audit_ptrace(struct aa_profile *profile, | |||
42 | { | 42 | { |
43 | struct common_audit_data sa; | 43 | struct common_audit_data sa; |
44 | struct apparmor_audit_data aad = {0,}; | 44 | struct apparmor_audit_data aad = {0,}; |
45 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 45 | sa.type = LSM_AUDIT_DATA_NONE; |
46 | sa.aad = &aad; | 46 | sa.aad = &aad; |
47 | aad.op = OP_PTRACE; | 47 | aad.op = OP_PTRACE; |
48 | aad.target = target; | 48 | aad.target = target; |
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index e75829ba0ff9..7430298116d6 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c | |||
@@ -66,7 +66,7 @@ void aa_info_message(const char *str) | |||
66 | if (audit_enabled) { | 66 | if (audit_enabled) { |
67 | struct common_audit_data sa; | 67 | struct common_audit_data sa; |
68 | struct apparmor_audit_data aad = {0,}; | 68 | struct apparmor_audit_data aad = {0,}; |
69 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 69 | sa.type = LSM_AUDIT_DATA_NONE; |
70 | sa.aad = &aad; | 70 | sa.aad = &aad; |
71 | aad.info = str; | 71 | aad.info = str; |
72 | aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); | 72 | aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); |
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index ad05d391974d..032daab449b0 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -373,7 +373,7 @@ static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
373 | AA_MAY_META_READ); | 373 | AA_MAY_META_READ); |
374 | } | 374 | } |
375 | 375 | ||
376 | static int apparmor_dentry_open(struct file *file, const struct cred *cred) | 376 | static int apparmor_file_open(struct file *file, const struct cred *cred) |
377 | { | 377 | { |
378 | struct aa_file_cxt *fcxt = file->f_security; | 378 | struct aa_file_cxt *fcxt = file->f_security; |
379 | struct aa_profile *profile; | 379 | struct aa_profile *profile; |
@@ -589,7 +589,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, | |||
589 | } else { | 589 | } else { |
590 | struct common_audit_data sa; | 590 | struct common_audit_data sa; |
591 | struct apparmor_audit_data aad = {0,}; | 591 | struct apparmor_audit_data aad = {0,}; |
592 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 592 | sa.type = LSM_AUDIT_DATA_NONE; |
593 | sa.aad = &aad; | 593 | sa.aad = &aad; |
594 | aad.op = OP_SETPROCATTR; | 594 | aad.op = OP_SETPROCATTR; |
595 | aad.info = name; | 595 | aad.info = name; |
@@ -640,9 +640,9 @@ static struct security_operations apparmor_ops = { | |||
640 | .path_chmod = apparmor_path_chmod, | 640 | .path_chmod = apparmor_path_chmod, |
641 | .path_chown = apparmor_path_chown, | 641 | .path_chown = apparmor_path_chown, |
642 | .path_truncate = apparmor_path_truncate, | 642 | .path_truncate = apparmor_path_truncate, |
643 | .dentry_open = apparmor_dentry_open, | ||
644 | .inode_getattr = apparmor_inode_getattr, | 643 | .inode_getattr = apparmor_inode_getattr, |
645 | 644 | ||
645 | .file_open = apparmor_file_open, | ||
646 | .file_permission = apparmor_file_permission, | 646 | .file_permission = apparmor_file_permission, |
647 | .file_alloc_security = apparmor_file_alloc_security, | 647 | .file_alloc_security = apparmor_file_alloc_security, |
648 | .file_free_security = apparmor_file_free_security, | 648 | .file_free_security = apparmor_file_free_security, |
diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 2daeea4f9266..e91ffee80162 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c | |||
@@ -94,6 +94,8 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, | |||
94 | * be returned. | 94 | * be returned. |
95 | */ | 95 | */ |
96 | if (!res || IS_ERR(res)) { | 96 | if (!res || IS_ERR(res)) { |
97 | if (PTR_ERR(res) == -ENAMETOOLONG) | ||
98 | return -ENAMETOOLONG; | ||
97 | connected = 0; | 99 | connected = 0; |
98 | res = dentry_path_raw(path->dentry, buf, buflen); | 100 | res = dentry_path_raw(path->dentry, buf, buflen); |
99 | if (IS_ERR(res)) { | 101 | if (IS_ERR(res)) { |
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index f1f7506a464d..cf5fd220309b 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c | |||
@@ -903,6 +903,10 @@ struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname) | |||
903 | profile = aa_get_profile(__lookup_profile(&ns->base, hname)); | 903 | profile = aa_get_profile(__lookup_profile(&ns->base, hname)); |
904 | read_unlock(&ns->lock); | 904 | read_unlock(&ns->lock); |
905 | 905 | ||
906 | /* the unconfined profile is not in the regular profile list */ | ||
907 | if (!profile && strcmp(hname, "unconfined") == 0) | ||
908 | profile = aa_get_profile(ns->unconfined); | ||
909 | |||
906 | /* refcount released by caller */ | 910 | /* refcount released by caller */ |
907 | return profile; | 911 | return profile; |
908 | } | 912 | } |
@@ -965,7 +969,7 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info, | |||
965 | { | 969 | { |
966 | struct common_audit_data sa; | 970 | struct common_audit_data sa; |
967 | struct apparmor_audit_data aad = {0,}; | 971 | struct apparmor_audit_data aad = {0,}; |
968 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 972 | sa.type = LSM_AUDIT_DATA_NONE; |
969 | sa.aad = &aad; | 973 | sa.aad = &aad; |
970 | aad.op = op; | 974 | aad.op = op; |
971 | aad.name = name; | 975 | aad.name = name; |
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index deab7c7e8dc0..329b1fd30749 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c | |||
@@ -95,7 +95,7 @@ static int audit_iface(struct aa_profile *new, const char *name, | |||
95 | struct aa_profile *profile = __aa_current_profile(); | 95 | struct aa_profile *profile = __aa_current_profile(); |
96 | struct common_audit_data sa; | 96 | struct common_audit_data sa; |
97 | struct apparmor_audit_data aad = {0,}; | 97 | struct apparmor_audit_data aad = {0,}; |
98 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 98 | sa.type = LSM_AUDIT_DATA_NONE; |
99 | sa.aad = &aad; | 99 | sa.aad = &aad; |
100 | if (e) | 100 | if (e) |
101 | aad.iface.pos = e->pos - e->start; | 101 | aad.iface.pos = e->pos - e->start; |
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index 2fe8613efe33..e1f3d7ef2c54 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c | |||
@@ -52,7 +52,7 @@ static int audit_resource(struct aa_profile *profile, unsigned int resource, | |||
52 | struct common_audit_data sa; | 52 | struct common_audit_data sa; |
53 | struct apparmor_audit_data aad = {0,}; | 53 | struct apparmor_audit_data aad = {0,}; |
54 | 54 | ||
55 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 55 | sa.type = LSM_AUDIT_DATA_NONE; |
56 | sa.aad = &aad; | 56 | sa.aad = &aad; |
57 | aad.op = OP_SETRLIMIT, | 57 | aad.op = OP_SETRLIMIT, |
58 | aad.rlim.rlim = resource; | 58 | aad.rlim.rlim = resource; |
diff --git a/security/capability.c b/security/capability.c index 5bb21b1c448c..fca889676c5e 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -348,7 +348,7 @@ static int cap_file_receive(struct file *file) | |||
348 | return 0; | 348 | return 0; |
349 | } | 349 | } |
350 | 350 | ||
351 | static int cap_dentry_open(struct file *file, const struct cred *cred) | 351 | static int cap_file_open(struct file *file, const struct cred *cred) |
352 | { | 352 | { |
353 | return 0; | 353 | return 0; |
354 | } | 354 | } |
@@ -956,7 +956,7 @@ void __init security_fixup_ops(struct security_operations *ops) | |||
956 | set_to_cap_if_null(ops, file_set_fowner); | 956 | set_to_cap_if_null(ops, file_set_fowner); |
957 | set_to_cap_if_null(ops, file_send_sigiotask); | 957 | set_to_cap_if_null(ops, file_send_sigiotask); |
958 | set_to_cap_if_null(ops, file_receive); | 958 | set_to_cap_if_null(ops, file_receive); |
959 | set_to_cap_if_null(ops, dentry_open); | 959 | set_to_cap_if_null(ops, file_open); |
960 | set_to_cap_if_null(ops, task_create); | 960 | set_to_cap_if_null(ops, task_create); |
961 | set_to_cap_if_null(ops, task_free); | 961 | set_to_cap_if_null(ops, task_free); |
962 | set_to_cap_if_null(ops, cred_alloc_blank); | 962 | set_to_cap_if_null(ops, cred_alloc_blank); |
diff --git a/security/commoncap.c b/security/commoncap.c index 71a166a05975..f80d11609391 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -512,14 +512,17 @@ skip: | |||
512 | 512 | ||
513 | 513 | ||
514 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised | 514 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised |
515 | * credentials unless they have the appropriate permit | 515 | * credentials unless they have the appropriate permit. |
516 | * | ||
517 | * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. | ||
516 | */ | 518 | */ |
517 | if ((new->euid != old->uid || | 519 | if ((new->euid != old->uid || |
518 | new->egid != old->gid || | 520 | new->egid != old->gid || |
519 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && | 521 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && |
520 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { | 522 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { |
521 | /* downgrade; they get no more than they had, and maybe less */ | 523 | /* downgrade; they get no more than they had, and maybe less */ |
522 | if (!capable(CAP_SETUID)) { | 524 | if (!capable(CAP_SETUID) || |
525 | (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) { | ||
523 | new->euid = new->uid; | 526 | new->euid = new->uid; |
524 | new->egid = new->gid; | 527 | new->egid = new->gid; |
525 | } | 528 | } |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 1eff5cb001e5..b17be79b9cf2 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -194,7 +194,9 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
194 | { | 194 | { |
195 | int rc; | 195 | int rc; |
196 | 196 | ||
197 | rc = process_measurement(bprm->file, bprm->filename, | 197 | rc = process_measurement(bprm->file, |
198 | (strcmp(bprm->filename, bprm->interp) == 0) ? | ||
199 | bprm->filename : bprm->interp, | ||
198 | MAY_EXEC, BPRM_CHECK); | 200 | MAY_EXEC, BPRM_CHECK); |
199 | return 0; | 201 | return 0; |
200 | } | 202 | } |
diff --git a/security/keys/Kconfig b/security/keys/Kconfig new file mode 100644 index 000000000000..a90d6d300dbd --- /dev/null +++ b/security/keys/Kconfig | |||
@@ -0,0 +1,71 @@ | |||
1 | # | ||
2 | # Key management configuration | ||
3 | # | ||
4 | |||
5 | config KEYS | ||
6 | bool "Enable access key retention support" | ||
7 | help | ||
8 | This option provides support for retaining authentication tokens and | ||
9 | access keys in the kernel. | ||
10 | |||
11 | It also includes provision of methods by which such keys might be | ||
12 | associated with a process so that network filesystems, encryption | ||
13 | support and the like can find them. | ||
14 | |||
15 | Furthermore, a special type of key is available that acts as keyring: | ||
16 | a searchable sequence of keys. Each process is equipped with access | ||
17 | to five standard keyrings: UID-specific, GID-specific, session, | ||
18 | process and thread. | ||
19 | |||
20 | If you are unsure as to whether this is required, answer N. | ||
21 | |||
22 | config TRUSTED_KEYS | ||
23 | tristate "TRUSTED KEYS" | ||
24 | depends on KEYS && TCG_TPM | ||
25 | select CRYPTO | ||
26 | select CRYPTO_HMAC | ||
27 | select CRYPTO_SHA1 | ||
28 | help | ||
29 | This option provides support for creating, sealing, and unsealing | ||
30 | keys in the kernel. Trusted keys are random number symmetric keys, | ||
31 | generated and RSA-sealed by the TPM. The TPM only unseals the keys, | ||
32 | if the boot PCRs and other criteria match. Userspace will only ever | ||
33 | see encrypted blobs. | ||
34 | |||
35 | If you are unsure as to whether this is required, answer N. | ||
36 | |||
37 | config ENCRYPTED_KEYS | ||
38 | tristate "ENCRYPTED KEYS" | ||
39 | depends on KEYS | ||
40 | select CRYPTO | ||
41 | select CRYPTO_HMAC | ||
42 | select CRYPTO_AES | ||
43 | select CRYPTO_CBC | ||
44 | select CRYPTO_SHA256 | ||
45 | select CRYPTO_RNG | ||
46 | help | ||
47 | This option provides support for create/encrypting/decrypting keys | ||
48 | in the kernel. Encrypted keys are kernel generated random numbers, | ||
49 | which are encrypted/decrypted with a 'master' symmetric key. The | ||
50 | 'master' key can be either a trusted-key or user-key type. | ||
51 | Userspace only ever sees/stores encrypted blobs. | ||
52 | |||
53 | If you are unsure as to whether this is required, answer N. | ||
54 | |||
55 | config KEYS_DEBUG_PROC_KEYS | ||
56 | bool "Enable the /proc/keys file by which keys may be viewed" | ||
57 | depends on KEYS | ||
58 | help | ||
59 | This option turns on support for the /proc/keys file - through which | ||
60 | can be listed all the keys on the system that are viewable by the | ||
61 | reading process. | ||
62 | |||
63 | The only keys included in the list are those that grant View | ||
64 | permission to the reading process whether or not it possesses them. | ||
65 | Note that LSM security checks are still performed, and may further | ||
66 | filter out keys that the current process is not authorised to view. | ||
67 | |||
68 | Only key attributes are listed here; key payloads are not included in | ||
69 | the resulting table. | ||
70 | |||
71 | If you are unsure as to whether this is required, answer N. | ||
diff --git a/security/keys/Makefile b/security/keys/Makefile index a56f1ffdc64d..504aaa008388 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
@@ -2,6 +2,9 @@ | |||
2 | # Makefile for key management | 2 | # Makefile for key management |
3 | # | 3 | # |
4 | 4 | ||
5 | # | ||
6 | # Core | ||
7 | # | ||
5 | obj-y := \ | 8 | obj-y := \ |
6 | gc.o \ | 9 | gc.o \ |
7 | key.o \ | 10 | key.o \ |
@@ -12,9 +15,12 @@ obj-y := \ | |||
12 | request_key.o \ | 15 | request_key.o \ |
13 | request_key_auth.o \ | 16 | request_key_auth.o \ |
14 | user_defined.o | 17 | user_defined.o |
15 | |||
16 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | ||
17 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ | ||
18 | obj-$(CONFIG_KEYS_COMPAT) += compat.o | 18 | obj-$(CONFIG_KEYS_COMPAT) += compat.o |
19 | obj-$(CONFIG_PROC_FS) += proc.o | 19 | obj-$(CONFIG_PROC_FS) += proc.o |
20 | obj-$(CONFIG_SYSCTL) += sysctl.o | 20 | obj-$(CONFIG_SYSCTL) += sysctl.o |
21 | |||
22 | # | ||
23 | # Key types | ||
24 | # | ||
25 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | ||
26 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ | ||
diff --git a/security/keys/compat.c b/security/keys/compat.c index 4c48e13448f8..fab4f8dda6c6 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
@@ -135,6 +135,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
135 | return compat_keyctl_instantiate_key_iov( | 135 | return compat_keyctl_instantiate_key_iov( |
136 | arg2, compat_ptr(arg3), arg4, arg5); | 136 | arg2, compat_ptr(arg3), arg4, arg5); |
137 | 137 | ||
138 | case KEYCTL_INVALIDATE: | ||
139 | return keyctl_invalidate_key(arg2); | ||
140 | |||
138 | default: | 141 | default: |
139 | return -EOPNOTSUPP; | 142 | return -EOPNOTSUPP; |
140 | } | 143 | } |
diff --git a/security/keys/gc.c b/security/keys/gc.c index a42b45531aac..61ab7c82ebb1 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
@@ -72,6 +72,15 @@ void key_schedule_gc(time_t gc_at) | |||
72 | } | 72 | } |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * Schedule a dead links collection run. | ||
76 | */ | ||
77 | void key_schedule_gc_links(void) | ||
78 | { | ||
79 | set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); | ||
80 | queue_work(system_nrt_wq, &key_gc_work); | ||
81 | } | ||
82 | |||
83 | /* | ||
75 | * Some key's cleanup time was met after it expired, so we need to get the | 84 | * Some key's cleanup time was met after it expired, so we need to get the |
76 | * reaper to go through a cycle finding expired keys. | 85 | * reaper to go through a cycle finding expired keys. |
77 | */ | 86 | */ |
@@ -79,8 +88,7 @@ static void key_gc_timer_func(unsigned long data) | |||
79 | { | 88 | { |
80 | kenter(""); | 89 | kenter(""); |
81 | key_gc_next_run = LONG_MAX; | 90 | key_gc_next_run = LONG_MAX; |
82 | set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); | 91 | key_schedule_gc_links(); |
83 | queue_work(system_nrt_wq, &key_gc_work); | ||
84 | } | 92 | } |
85 | 93 | ||
86 | /* | 94 | /* |
@@ -131,12 +139,12 @@ void key_gc_keytype(struct key_type *ktype) | |||
131 | static void key_gc_keyring(struct key *keyring, time_t limit) | 139 | static void key_gc_keyring(struct key *keyring, time_t limit) |
132 | { | 140 | { |
133 | struct keyring_list *klist; | 141 | struct keyring_list *klist; |
134 | struct key *key; | ||
135 | int loop; | 142 | int loop; |
136 | 143 | ||
137 | kenter("%x", key_serial(keyring)); | 144 | kenter("%x", key_serial(keyring)); |
138 | 145 | ||
139 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 146 | if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | |
147 | (1 << KEY_FLAG_REVOKED))) | ||
140 | goto dont_gc; | 148 | goto dont_gc; |
141 | 149 | ||
142 | /* scan the keyring looking for dead keys */ | 150 | /* scan the keyring looking for dead keys */ |
@@ -148,9 +156,8 @@ static void key_gc_keyring(struct key *keyring, time_t limit) | |||
148 | loop = klist->nkeys; | 156 | loop = klist->nkeys; |
149 | smp_rmb(); | 157 | smp_rmb(); |
150 | for (loop--; loop >= 0; loop--) { | 158 | for (loop--; loop >= 0; loop--) { |
151 | key = klist->keys[loop]; | 159 | struct key *key = rcu_dereference(klist->keys[loop]); |
152 | if (test_bit(KEY_FLAG_DEAD, &key->flags) || | 160 | if (key_is_dead(key, limit)) |
153 | (key->expiry > 0 && key->expiry <= limit)) | ||
154 | goto do_gc; | 161 | goto do_gc; |
155 | } | 162 | } |
156 | 163 | ||
@@ -168,38 +175,45 @@ do_gc: | |||
168 | } | 175 | } |
169 | 176 | ||
170 | /* | 177 | /* |
171 | * Garbage collect an unreferenced, detached key | 178 | * Garbage collect a list of unreferenced, detached keys |
172 | */ | 179 | */ |
173 | static noinline void key_gc_unused_key(struct key *key) | 180 | static noinline void key_gc_unused_keys(struct list_head *keys) |
174 | { | 181 | { |
175 | key_check(key); | 182 | while (!list_empty(keys)) { |
176 | 183 | struct key *key = | |
177 | security_key_free(key); | 184 | list_entry(keys->next, struct key, graveyard_link); |
178 | 185 | list_del(&key->graveyard_link); | |
179 | /* deal with the user's key tracking and quota */ | 186 | |
180 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 187 | kdebug("- %u", key->serial); |
181 | spin_lock(&key->user->lock); | 188 | key_check(key); |
182 | key->user->qnkeys--; | 189 | |
183 | key->user->qnbytes -= key->quotalen; | 190 | security_key_free(key); |
184 | spin_unlock(&key->user->lock); | 191 | |
185 | } | 192 | /* deal with the user's key tracking and quota */ |
193 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | ||
194 | spin_lock(&key->user->lock); | ||
195 | key->user->qnkeys--; | ||
196 | key->user->qnbytes -= key->quotalen; | ||
197 | spin_unlock(&key->user->lock); | ||
198 | } | ||
186 | 199 | ||
187 | atomic_dec(&key->user->nkeys); | 200 | atomic_dec(&key->user->nkeys); |
188 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 201 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
189 | atomic_dec(&key->user->nikeys); | 202 | atomic_dec(&key->user->nikeys); |
190 | 203 | ||
191 | key_user_put(key->user); | 204 | key_user_put(key->user); |
192 | 205 | ||
193 | /* now throw away the key memory */ | 206 | /* now throw away the key memory */ |
194 | if (key->type->destroy) | 207 | if (key->type->destroy) |
195 | key->type->destroy(key); | 208 | key->type->destroy(key); |
196 | 209 | ||
197 | kfree(key->description); | 210 | kfree(key->description); |
198 | 211 | ||
199 | #ifdef KEY_DEBUGGING | 212 | #ifdef KEY_DEBUGGING |
200 | key->magic = KEY_DEBUG_MAGIC_X; | 213 | key->magic = KEY_DEBUG_MAGIC_X; |
201 | #endif | 214 | #endif |
202 | kmem_cache_free(key_jar, key); | 215 | kmem_cache_free(key_jar, key); |
216 | } | ||
203 | } | 217 | } |
204 | 218 | ||
205 | /* | 219 | /* |
@@ -211,6 +225,7 @@ static noinline void key_gc_unused_key(struct key *key) | |||
211 | */ | 225 | */ |
212 | static void key_garbage_collector(struct work_struct *work) | 226 | static void key_garbage_collector(struct work_struct *work) |
213 | { | 227 | { |
228 | static LIST_HEAD(graveyard); | ||
214 | static u8 gc_state; /* Internal persistent state */ | 229 | static u8 gc_state; /* Internal persistent state */ |
215 | #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ | 230 | #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ |
216 | #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ | 231 | #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ |
@@ -316,15 +331,22 @@ maybe_resched: | |||
316 | key_schedule_gc(new_timer); | 331 | key_schedule_gc(new_timer); |
317 | } | 332 | } |
318 | 333 | ||
319 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) { | 334 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2) || |
320 | /* Make sure everyone revalidates their keys if we marked a | 335 | !list_empty(&graveyard)) { |
321 | * bunch as being dead and make sure all keyring ex-payloads | 336 | /* Make sure that all pending keyring payload destructions are |
322 | * are destroyed. | 337 | * fulfilled and that people aren't now looking at dead or |
338 | * dying keys that they don't have a reference upon or a link | ||
339 | * to. | ||
323 | */ | 340 | */ |
324 | kdebug("dead sync"); | 341 | kdebug("gc sync"); |
325 | synchronize_rcu(); | 342 | synchronize_rcu(); |
326 | } | 343 | } |
327 | 344 | ||
345 | if (!list_empty(&graveyard)) { | ||
346 | kdebug("gc keys"); | ||
347 | key_gc_unused_keys(&graveyard); | ||
348 | } | ||
349 | |||
328 | if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | | 350 | if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | |
329 | KEY_GC_REAPING_DEAD_2))) { | 351 | KEY_GC_REAPING_DEAD_2))) { |
330 | if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { | 352 | if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { |
@@ -359,7 +381,7 @@ found_unreferenced_key: | |||
359 | rb_erase(&key->serial_node, &key_serial_tree); | 381 | rb_erase(&key->serial_node, &key_serial_tree); |
360 | spin_unlock(&key_serial_lock); | 382 | spin_unlock(&key_serial_lock); |
361 | 383 | ||
362 | key_gc_unused_key(key); | 384 | list_add_tail(&key->graveyard_link, &graveyard); |
363 | gc_state |= KEY_GC_REAP_AGAIN; | 385 | gc_state |= KEY_GC_REAP_AGAIN; |
364 | goto maybe_resched; | 386 | goto maybe_resched; |
365 | 387 | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 65647f825584..f711b094ed41 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -152,7 +152,8 @@ extern long join_session_keyring(const char *name); | |||
152 | extern struct work_struct key_gc_work; | 152 | extern struct work_struct key_gc_work; |
153 | extern unsigned key_gc_delay; | 153 | extern unsigned key_gc_delay; |
154 | extern void keyring_gc(struct key *keyring, time_t limit); | 154 | extern void keyring_gc(struct key *keyring, time_t limit); |
155 | extern void key_schedule_gc(time_t expiry_at); | 155 | extern void key_schedule_gc(time_t gc_at); |
156 | extern void key_schedule_gc_links(void); | ||
156 | extern void key_gc_keytype(struct key_type *ktype); | 157 | extern void key_gc_keytype(struct key_type *ktype); |
157 | 158 | ||
158 | extern int key_task_permission(const key_ref_t key_ref, | 159 | extern int key_task_permission(const key_ref_t key_ref, |
@@ -197,6 +198,17 @@ extern struct key *request_key_auth_new(struct key *target, | |||
197 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); | 198 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); |
198 | 199 | ||
199 | /* | 200 | /* |
201 | * Determine whether a key is dead. | ||
202 | */ | ||
203 | static inline bool key_is_dead(struct key *key, time_t limit) | ||
204 | { | ||
205 | return | ||
206 | key->flags & ((1 << KEY_FLAG_DEAD) | | ||
207 | (1 << KEY_FLAG_INVALIDATED)) || | ||
208 | (key->expiry > 0 && key->expiry <= limit); | ||
209 | } | ||
210 | |||
211 | /* | ||
200 | * keyctl() functions | 212 | * keyctl() functions |
201 | */ | 213 | */ |
202 | extern long keyctl_get_keyring_ID(key_serial_t, int); | 214 | extern long keyctl_get_keyring_ID(key_serial_t, int); |
@@ -225,6 +237,7 @@ extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t); | |||
225 | extern long keyctl_instantiate_key_iov(key_serial_t, | 237 | extern long keyctl_instantiate_key_iov(key_serial_t, |
226 | const struct iovec __user *, | 238 | const struct iovec __user *, |
227 | unsigned, key_serial_t); | 239 | unsigned, key_serial_t); |
240 | extern long keyctl_invalidate_key(key_serial_t); | ||
228 | 241 | ||
229 | extern long keyctl_instantiate_key_common(key_serial_t, | 242 | extern long keyctl_instantiate_key_common(key_serial_t, |
230 | const struct iovec __user *, | 243 | const struct iovec __user *, |
diff --git a/security/keys/key.c b/security/keys/key.c index 06783cffb3af..c9bf66ac36e0 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -955,6 +955,28 @@ void key_revoke(struct key *key) | |||
955 | EXPORT_SYMBOL(key_revoke); | 955 | EXPORT_SYMBOL(key_revoke); |
956 | 956 | ||
957 | /** | 957 | /** |
958 | * key_invalidate - Invalidate a key. | ||
959 | * @key: The key to be invalidated. | ||
960 | * | ||
961 | * Mark a key as being invalidated and have it cleaned up immediately. The key | ||
962 | * is ignored by all searches and other operations from this point. | ||
963 | */ | ||
964 | void key_invalidate(struct key *key) | ||
965 | { | ||
966 | kenter("%d", key_serial(key)); | ||
967 | |||
968 | key_check(key); | ||
969 | |||
970 | if (!test_bit(KEY_FLAG_INVALIDATED, &key->flags)) { | ||
971 | down_write_nested(&key->sem, 1); | ||
972 | if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) | ||
973 | key_schedule_gc_links(); | ||
974 | up_write(&key->sem); | ||
975 | } | ||
976 | } | ||
977 | EXPORT_SYMBOL(key_invalidate); | ||
978 | |||
979 | /** | ||
958 | * register_key_type - Register a type of key. | 980 | * register_key_type - Register a type of key. |
959 | * @ktype: The new key type. | 981 | * @ktype: The new key type. |
960 | * | 982 | * |
@@ -980,6 +1002,8 @@ int register_key_type(struct key_type *ktype) | |||
980 | 1002 | ||
981 | /* store the type */ | 1003 | /* store the type */ |
982 | list_add(&ktype->link, &key_types_list); | 1004 | list_add(&ktype->link, &key_types_list); |
1005 | |||
1006 | pr_notice("Key type %s registered\n", ktype->name); | ||
983 | ret = 0; | 1007 | ret = 0; |
984 | 1008 | ||
985 | out: | 1009 | out: |
@@ -1002,6 +1026,7 @@ void unregister_key_type(struct key_type *ktype) | |||
1002 | list_del_init(&ktype->link); | 1026 | list_del_init(&ktype->link); |
1003 | downgrade_write(&key_types_sem); | 1027 | downgrade_write(&key_types_sem); |
1004 | key_gc_keytype(ktype); | 1028 | key_gc_keytype(ktype); |
1029 | pr_notice("Key type %s unregistered\n", ktype->name); | ||
1005 | up_read(&key_types_sem); | 1030 | up_read(&key_types_sem); |
1006 | } | 1031 | } |
1007 | EXPORT_SYMBOL(unregister_key_type); | 1032 | EXPORT_SYMBOL(unregister_key_type); |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index fb767c6cd99f..ddb3e05bc5fc 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -375,6 +375,37 @@ error: | |||
375 | } | 375 | } |
376 | 376 | ||
377 | /* | 377 | /* |
378 | * Invalidate a key. | ||
379 | * | ||
380 | * The key must be grant the caller Invalidate permission for this to work. | ||
381 | * The key and any links to the key will be automatically garbage collected | ||
382 | * immediately. | ||
383 | * | ||
384 | * If successful, 0 is returned. | ||
385 | */ | ||
386 | long keyctl_invalidate_key(key_serial_t id) | ||
387 | { | ||
388 | key_ref_t key_ref; | ||
389 | long ret; | ||
390 | |||
391 | kenter("%d", id); | ||
392 | |||
393 | key_ref = lookup_user_key(id, 0, KEY_SEARCH); | ||
394 | if (IS_ERR(key_ref)) { | ||
395 | ret = PTR_ERR(key_ref); | ||
396 | goto error; | ||
397 | } | ||
398 | |||
399 | key_invalidate(key_ref_to_ptr(key_ref)); | ||
400 | ret = 0; | ||
401 | |||
402 | key_ref_put(key_ref); | ||
403 | error: | ||
404 | kleave(" = %ld", ret); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | /* | ||
378 | * Clear the specified keyring, creating an empty process keyring if one of the | 409 | * Clear the specified keyring, creating an empty process keyring if one of the |
379 | * special keyring IDs is used. | 410 | * special keyring IDs is used. |
380 | * | 411 | * |
@@ -1622,6 +1653,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1622 | (unsigned) arg4, | 1653 | (unsigned) arg4, |
1623 | (key_serial_t) arg5); | 1654 | (key_serial_t) arg5); |
1624 | 1655 | ||
1656 | case KEYCTL_INVALIDATE: | ||
1657 | return keyctl_invalidate_key((key_serial_t) arg2); | ||
1658 | |||
1625 | default: | 1659 | default: |
1626 | return -EOPNOTSUPP; | 1660 | return -EOPNOTSUPP; |
1627 | } | 1661 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index d605f75292e4..7445875f6818 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -25,6 +25,15 @@ | |||
25 | (keyring)->payload.subscriptions, \ | 25 | (keyring)->payload.subscriptions, \ |
26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | 26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) |
27 | 27 | ||
28 | #define rcu_deref_link_locked(klist, index, keyring) \ | ||
29 | (rcu_dereference_protected( \ | ||
30 | (klist)->keys[index], \ | ||
31 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | ||
32 | |||
33 | #define MAX_KEYRING_LINKS \ | ||
34 | min_t(size_t, USHRT_MAX - 1, \ | ||
35 | ((PAGE_SIZE - sizeof(struct keyring_list)) / sizeof(struct key *))) | ||
36 | |||
28 | #define KEY_LINK_FIXQUOTA 1UL | 37 | #define KEY_LINK_FIXQUOTA 1UL |
29 | 38 | ||
30 | /* | 39 | /* |
@@ -138,6 +147,11 @@ static int keyring_match(const struct key *keyring, const void *description) | |||
138 | /* | 147 | /* |
139 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one | 148 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one |
140 | * and dispose of its data. | 149 | * and dispose of its data. |
150 | * | ||
151 | * The garbage collector detects the final key_put(), removes the keyring from | ||
152 | * the serial number tree and then does RCU synchronisation before coming here, | ||
153 | * so we shouldn't need to worry about code poking around here with the RCU | ||
154 | * readlock held by this time. | ||
141 | */ | 155 | */ |
142 | static void keyring_destroy(struct key *keyring) | 156 | static void keyring_destroy(struct key *keyring) |
143 | { | 157 | { |
@@ -154,11 +168,10 @@ static void keyring_destroy(struct key *keyring) | |||
154 | write_unlock(&keyring_name_lock); | 168 | write_unlock(&keyring_name_lock); |
155 | } | 169 | } |
156 | 170 | ||
157 | klist = rcu_dereference_check(keyring->payload.subscriptions, | 171 | klist = rcu_access_pointer(keyring->payload.subscriptions); |
158 | atomic_read(&keyring->usage) == 0); | ||
159 | if (klist) { | 172 | if (klist) { |
160 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 173 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
161 | key_put(klist->keys[loop]); | 174 | key_put(rcu_access_pointer(klist->keys[loop])); |
162 | kfree(klist); | 175 | kfree(klist); |
163 | } | 176 | } |
164 | } | 177 | } |
@@ -214,7 +227,8 @@ static long keyring_read(const struct key *keyring, | |||
214 | ret = -EFAULT; | 227 | ret = -EFAULT; |
215 | 228 | ||
216 | for (loop = 0; loop < klist->nkeys; loop++) { | 229 | for (loop = 0; loop < klist->nkeys; loop++) { |
217 | key = klist->keys[loop]; | 230 | key = rcu_deref_link_locked(klist, loop, |
231 | keyring); | ||
218 | 232 | ||
219 | tmp = sizeof(key_serial_t); | 233 | tmp = sizeof(key_serial_t); |
220 | if (tmp > buflen) | 234 | if (tmp > buflen) |
@@ -309,6 +323,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
309 | bool no_state_check) | 323 | bool no_state_check) |
310 | { | 324 | { |
311 | struct { | 325 | struct { |
326 | /* Need a separate keylist pointer for RCU purposes */ | ||
327 | struct key *keyring; | ||
312 | struct keyring_list *keylist; | 328 | struct keyring_list *keylist; |
313 | int kix; | 329 | int kix; |
314 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 330 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
@@ -366,13 +382,17 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
366 | /* otherwise, the top keyring must not be revoked, expired, or | 382 | /* otherwise, the top keyring must not be revoked, expired, or |
367 | * negatively instantiated if we are to search it */ | 383 | * negatively instantiated if we are to search it */ |
368 | key_ref = ERR_PTR(-EAGAIN); | 384 | key_ref = ERR_PTR(-EAGAIN); |
369 | if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || | 385 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
386 | (1 << KEY_FLAG_REVOKED) | | ||
387 | (1 << KEY_FLAG_NEGATIVE)) || | ||
370 | (keyring->expiry && now.tv_sec >= keyring->expiry)) | 388 | (keyring->expiry && now.tv_sec >= keyring->expiry)) |
371 | goto error_2; | 389 | goto error_2; |
372 | 390 | ||
373 | /* start processing a new keyring */ | 391 | /* start processing a new keyring */ |
374 | descend: | 392 | descend: |
375 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 393 | kflags = keyring->flags; |
394 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | | ||
395 | (1 << KEY_FLAG_REVOKED))) | ||
376 | goto not_this_keyring; | 396 | goto not_this_keyring; |
377 | 397 | ||
378 | keylist = rcu_dereference(keyring->payload.subscriptions); | 398 | keylist = rcu_dereference(keyring->payload.subscriptions); |
@@ -383,16 +403,17 @@ descend: | |||
383 | nkeys = keylist->nkeys; | 403 | nkeys = keylist->nkeys; |
384 | smp_rmb(); | 404 | smp_rmb(); |
385 | for (kix = 0; kix < nkeys; kix++) { | 405 | for (kix = 0; kix < nkeys; kix++) { |
386 | key = keylist->keys[kix]; | 406 | key = rcu_dereference(keylist->keys[kix]); |
387 | kflags = key->flags; | 407 | kflags = key->flags; |
388 | 408 | ||
389 | /* ignore keys not of this type */ | 409 | /* ignore keys not of this type */ |
390 | if (key->type != type) | 410 | if (key->type != type) |
391 | continue; | 411 | continue; |
392 | 412 | ||
393 | /* skip revoked keys and expired keys */ | 413 | /* skip invalidated, revoked and expired keys */ |
394 | if (!no_state_check) { | 414 | if (!no_state_check) { |
395 | if (kflags & (1 << KEY_FLAG_REVOKED)) | 415 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
416 | (1 << KEY_FLAG_REVOKED))) | ||
396 | continue; | 417 | continue; |
397 | 418 | ||
398 | if (key->expiry && now.tv_sec >= key->expiry) | 419 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -426,7 +447,7 @@ ascend: | |||
426 | nkeys = keylist->nkeys; | 447 | nkeys = keylist->nkeys; |
427 | smp_rmb(); | 448 | smp_rmb(); |
428 | for (; kix < nkeys; kix++) { | 449 | for (; kix < nkeys; kix++) { |
429 | key = keylist->keys[kix]; | 450 | key = rcu_dereference(keylist->keys[kix]); |
430 | if (key->type != &key_type_keyring) | 451 | if (key->type != &key_type_keyring) |
431 | continue; | 452 | continue; |
432 | 453 | ||
@@ -441,6 +462,7 @@ ascend: | |||
441 | continue; | 462 | continue; |
442 | 463 | ||
443 | /* stack the current position */ | 464 | /* stack the current position */ |
465 | stack[sp].keyring = keyring; | ||
444 | stack[sp].keylist = keylist; | 466 | stack[sp].keylist = keylist; |
445 | stack[sp].kix = kix; | 467 | stack[sp].kix = kix; |
446 | sp++; | 468 | sp++; |
@@ -456,6 +478,7 @@ not_this_keyring: | |||
456 | if (sp > 0) { | 478 | if (sp > 0) { |
457 | /* resume the processing of a keyring higher up in the tree */ | 479 | /* resume the processing of a keyring higher up in the tree */ |
458 | sp--; | 480 | sp--; |
481 | keyring = stack[sp].keyring; | ||
459 | keylist = stack[sp].keylist; | 482 | keylist = stack[sp].keylist; |
460 | kix = stack[sp].kix + 1; | 483 | kix = stack[sp].kix + 1; |
461 | goto ascend; | 484 | goto ascend; |
@@ -467,6 +490,10 @@ not_this_keyring: | |||
467 | /* we found a viable match */ | 490 | /* we found a viable match */ |
468 | found: | 491 | found: |
469 | atomic_inc(&key->usage); | 492 | atomic_inc(&key->usage); |
493 | key->last_used_at = now.tv_sec; | ||
494 | keyring->last_used_at = now.tv_sec; | ||
495 | while (sp > 0) | ||
496 | stack[--sp].keyring->last_used_at = now.tv_sec; | ||
470 | key_check(key); | 497 | key_check(key); |
471 | key_ref = make_key_ref(key, possessed); | 498 | key_ref = make_key_ref(key, possessed); |
472 | error_2: | 499 | error_2: |
@@ -531,14 +558,14 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
531 | nkeys = klist->nkeys; | 558 | nkeys = klist->nkeys; |
532 | smp_rmb(); | 559 | smp_rmb(); |
533 | for (loop = 0; loop < nkeys ; loop++) { | 560 | for (loop = 0; loop < nkeys ; loop++) { |
534 | key = klist->keys[loop]; | 561 | key = rcu_dereference(klist->keys[loop]); |
535 | |||
536 | if (key->type == ktype && | 562 | if (key->type == ktype && |
537 | (!key->type->match || | 563 | (!key->type->match || |
538 | key->type->match(key, description)) && | 564 | key->type->match(key, description)) && |
539 | key_permission(make_key_ref(key, possessed), | 565 | key_permission(make_key_ref(key, possessed), |
540 | perm) == 0 && | 566 | perm) == 0 && |
541 | !test_bit(KEY_FLAG_REVOKED, &key->flags) | 567 | !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | |
568 | (1 << KEY_FLAG_REVOKED))) | ||
542 | ) | 569 | ) |
543 | goto found; | 570 | goto found; |
544 | } | 571 | } |
@@ -549,6 +576,8 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
549 | 576 | ||
550 | found: | 577 | found: |
551 | atomic_inc(&key->usage); | 578 | atomic_inc(&key->usage); |
579 | keyring->last_used_at = key->last_used_at = | ||
580 | current_kernel_time().tv_sec; | ||
552 | rcu_read_unlock(); | 581 | rcu_read_unlock(); |
553 | return make_key_ref(key, possessed); | 582 | return make_key_ref(key, possessed); |
554 | } | 583 | } |
@@ -602,6 +631,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
602 | * (ie. it has a zero usage count) */ | 631 | * (ie. it has a zero usage count) */ |
603 | if (!atomic_inc_not_zero(&keyring->usage)) | 632 | if (!atomic_inc_not_zero(&keyring->usage)) |
604 | continue; | 633 | continue; |
634 | keyring->last_used_at = current_kernel_time().tv_sec; | ||
605 | goto out; | 635 | goto out; |
606 | } | 636 | } |
607 | } | 637 | } |
@@ -654,7 +684,7 @@ ascend: | |||
654 | nkeys = keylist->nkeys; | 684 | nkeys = keylist->nkeys; |
655 | smp_rmb(); | 685 | smp_rmb(); |
656 | for (; kix < nkeys; kix++) { | 686 | for (; kix < nkeys; kix++) { |
657 | key = keylist->keys[kix]; | 687 | key = rcu_dereference(keylist->keys[kix]); |
658 | 688 | ||
659 | if (key == A) | 689 | if (key == A) |
660 | goto cycle_detected; | 690 | goto cycle_detected; |
@@ -711,7 +741,7 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | |||
711 | container_of(rcu, struct keyring_list, rcu); | 741 | container_of(rcu, struct keyring_list, rcu); |
712 | 742 | ||
713 | if (klist->delkey != USHRT_MAX) | 743 | if (klist->delkey != USHRT_MAX) |
714 | key_put(klist->keys[klist->delkey]); | 744 | key_put(rcu_access_pointer(klist->keys[klist->delkey])); |
715 | kfree(klist); | 745 | kfree(klist); |
716 | } | 746 | } |
717 | 747 | ||
@@ -725,8 +755,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
725 | struct keyring_list *klist, *nklist; | 755 | struct keyring_list *klist, *nklist; |
726 | unsigned long prealloc; | 756 | unsigned long prealloc; |
727 | unsigned max; | 757 | unsigned max; |
758 | time_t lowest_lru; | ||
728 | size_t size; | 759 | size_t size; |
729 | int loop, ret; | 760 | int loop, lru, ret; |
730 | 761 | ||
731 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); | 762 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); |
732 | 763 | ||
@@ -747,31 +778,39 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
747 | klist = rcu_dereference_locked_keyring(keyring); | 778 | klist = rcu_dereference_locked_keyring(keyring); |
748 | 779 | ||
749 | /* see if there's a matching key we can displace */ | 780 | /* see if there's a matching key we can displace */ |
781 | lru = -1; | ||
750 | if (klist && klist->nkeys > 0) { | 782 | if (klist && klist->nkeys > 0) { |
783 | lowest_lru = TIME_T_MAX; | ||
751 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 784 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
752 | if (klist->keys[loop]->type == type && | 785 | struct key *key = rcu_deref_link_locked(klist, loop, |
753 | strcmp(klist->keys[loop]->description, | 786 | keyring); |
754 | description) == 0 | 787 | if (key->type == type && |
755 | ) { | 788 | strcmp(key->description, description) == 0) { |
756 | /* found a match - we'll replace this one with | 789 | /* Found a match - we'll replace the link with |
757 | * the new key */ | 790 | * one to the new key. We record the slot |
758 | size = sizeof(struct key *) * klist->maxkeys; | 791 | * position. |
759 | size += sizeof(*klist); | 792 | */ |
760 | BUG_ON(size > PAGE_SIZE); | 793 | klist->delkey = loop; |
761 | 794 | prealloc = 0; | |
762 | ret = -ENOMEM; | ||
763 | nklist = kmemdup(klist, size, GFP_KERNEL); | ||
764 | if (!nklist) | ||
765 | goto error_sem; | ||
766 | |||
767 | /* note replacement slot */ | ||
768 | klist->delkey = nklist->delkey = loop; | ||
769 | prealloc = (unsigned long)nklist; | ||
770 | goto done; | 795 | goto done; |
771 | } | 796 | } |
797 | if (key->last_used_at < lowest_lru) { | ||
798 | lowest_lru = key->last_used_at; | ||
799 | lru = loop; | ||
800 | } | ||
772 | } | 801 | } |
773 | } | 802 | } |
774 | 803 | ||
804 | /* If the keyring is full then do an LRU discard */ | ||
805 | if (klist && | ||
806 | klist->nkeys == klist->maxkeys && | ||
807 | klist->maxkeys >= MAX_KEYRING_LINKS) { | ||
808 | kdebug("LRU discard %d\n", lru); | ||
809 | klist->delkey = lru; | ||
810 | prealloc = 0; | ||
811 | goto done; | ||
812 | } | ||
813 | |||
775 | /* check that we aren't going to overrun the user's quota */ | 814 | /* check that we aren't going to overrun the user's quota */ |
776 | ret = key_payload_reserve(keyring, | 815 | ret = key_payload_reserve(keyring, |
777 | keyring->datalen + KEYQUOTA_LINK_BYTES); | 816 | keyring->datalen + KEYQUOTA_LINK_BYTES); |
@@ -780,20 +819,19 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
780 | 819 | ||
781 | if (klist && klist->nkeys < klist->maxkeys) { | 820 | if (klist && klist->nkeys < klist->maxkeys) { |
782 | /* there's sufficient slack space to append directly */ | 821 | /* there's sufficient slack space to append directly */ |
783 | nklist = NULL; | 822 | klist->delkey = klist->nkeys; |
784 | prealloc = KEY_LINK_FIXQUOTA; | 823 | prealloc = KEY_LINK_FIXQUOTA; |
785 | } else { | 824 | } else { |
786 | /* grow the key list */ | 825 | /* grow the key list */ |
787 | max = 4; | 826 | max = 4; |
788 | if (klist) | 827 | if (klist) { |
789 | max += klist->maxkeys; | 828 | max += klist->maxkeys; |
829 | if (max > MAX_KEYRING_LINKS) | ||
830 | max = MAX_KEYRING_LINKS; | ||
831 | BUG_ON(max <= klist->maxkeys); | ||
832 | } | ||
790 | 833 | ||
791 | ret = -ENFILE; | ||
792 | if (max > USHRT_MAX - 1) | ||
793 | goto error_quota; | ||
794 | size = sizeof(*klist) + sizeof(struct key *) * max; | 834 | size = sizeof(*klist) + sizeof(struct key *) * max; |
795 | if (size > PAGE_SIZE) | ||
796 | goto error_quota; | ||
797 | 835 | ||
798 | ret = -ENOMEM; | 836 | ret = -ENOMEM; |
799 | nklist = kmalloc(size, GFP_KERNEL); | 837 | nklist = kmalloc(size, GFP_KERNEL); |
@@ -813,10 +851,10 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
813 | } | 851 | } |
814 | 852 | ||
815 | /* add the key into the new space */ | 853 | /* add the key into the new space */ |
816 | nklist->keys[nklist->delkey] = NULL; | 854 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], NULL); |
855 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
817 | } | 856 | } |
818 | 857 | ||
819 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
820 | done: | 858 | done: |
821 | *_prealloc = prealloc; | 859 | *_prealloc = prealloc; |
822 | kleave(" = 0"); | 860 | kleave(" = 0"); |
@@ -862,6 +900,7 @@ void __key_link(struct key *keyring, struct key *key, | |||
862 | unsigned long *_prealloc) | 900 | unsigned long *_prealloc) |
863 | { | 901 | { |
864 | struct keyring_list *klist, *nklist; | 902 | struct keyring_list *klist, *nklist; |
903 | struct key *discard; | ||
865 | 904 | ||
866 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); | 905 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); |
867 | *_prealloc = 0; | 906 | *_prealloc = 0; |
@@ -871,14 +910,16 @@ void __key_link(struct key *keyring, struct key *key, | |||
871 | klist = rcu_dereference_locked_keyring(keyring); | 910 | klist = rcu_dereference_locked_keyring(keyring); |
872 | 911 | ||
873 | atomic_inc(&key->usage); | 912 | atomic_inc(&key->usage); |
913 | keyring->last_used_at = key->last_used_at = | ||
914 | current_kernel_time().tv_sec; | ||
874 | 915 | ||
875 | /* there's a matching key we can displace or an empty slot in a newly | 916 | /* there's a matching key we can displace or an empty slot in a newly |
876 | * allocated list we can fill */ | 917 | * allocated list we can fill */ |
877 | if (nklist) { | 918 | if (nklist) { |
878 | kdebug("replace %hu/%hu/%hu", | 919 | kdebug("reissue %hu/%hu/%hu", |
879 | nklist->delkey, nklist->nkeys, nklist->maxkeys); | 920 | nklist->delkey, nklist->nkeys, nklist->maxkeys); |
880 | 921 | ||
881 | nklist->keys[nklist->delkey] = key; | 922 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], key); |
882 | 923 | ||
883 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | 924 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
884 | 925 | ||
@@ -889,9 +930,23 @@ void __key_link(struct key *keyring, struct key *key, | |||
889 | klist->delkey, klist->nkeys, klist->maxkeys); | 930 | klist->delkey, klist->nkeys, klist->maxkeys); |
890 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | 931 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); |
891 | } | 932 | } |
933 | } else if (klist->delkey < klist->nkeys) { | ||
934 | kdebug("replace %hu/%hu/%hu", | ||
935 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
936 | |||
937 | discard = rcu_dereference_protected( | ||
938 | klist->keys[klist->delkey], | ||
939 | rwsem_is_locked(&keyring->sem)); | ||
940 | rcu_assign_pointer(klist->keys[klist->delkey], key); | ||
941 | /* The garbage collector will take care of RCU | ||
942 | * synchronisation */ | ||
943 | key_put(discard); | ||
892 | } else { | 944 | } else { |
893 | /* there's sufficient slack space to append directly */ | 945 | /* there's sufficient slack space to append directly */ |
894 | klist->keys[klist->nkeys] = key; | 946 | kdebug("append %hu/%hu/%hu", |
947 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
948 | |||
949 | RCU_INIT_POINTER(klist->keys[klist->delkey], key); | ||
895 | smp_wmb(); | 950 | smp_wmb(); |
896 | klist->nkeys++; | 951 | klist->nkeys++; |
897 | } | 952 | } |
@@ -998,7 +1053,7 @@ int key_unlink(struct key *keyring, struct key *key) | |||
998 | if (klist) { | 1053 | if (klist) { |
999 | /* search the keyring for the key */ | 1054 | /* search the keyring for the key */ |
1000 | for (loop = 0; loop < klist->nkeys; loop++) | 1055 | for (loop = 0; loop < klist->nkeys; loop++) |
1001 | if (klist->keys[loop] == key) | 1056 | if (rcu_access_pointer(klist->keys[loop]) == key) |
1002 | goto key_is_present; | 1057 | goto key_is_present; |
1003 | } | 1058 | } |
1004 | 1059 | ||
@@ -1061,7 +1116,7 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu) | |||
1061 | klist = container_of(rcu, struct keyring_list, rcu); | 1116 | klist = container_of(rcu, struct keyring_list, rcu); |
1062 | 1117 | ||
1063 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1118 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1064 | key_put(klist->keys[loop]); | 1119 | key_put(rcu_access_pointer(klist->keys[loop])); |
1065 | 1120 | ||
1066 | kfree(klist); | 1121 | kfree(klist); |
1067 | } | 1122 | } |
@@ -1128,15 +1183,6 @@ static void keyring_revoke(struct key *keyring) | |||
1128 | } | 1183 | } |
1129 | 1184 | ||
1130 | /* | 1185 | /* |
1131 | * Determine whether a key is dead. | ||
1132 | */ | ||
1133 | static bool key_is_dead(struct key *key, time_t limit) | ||
1134 | { | ||
1135 | return test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
1136 | (key->expiry > 0 && key->expiry <= limit); | ||
1137 | } | ||
1138 | |||
1139 | /* | ||
1140 | * Collect garbage from the contents of a keyring, replacing the old list with | 1186 | * Collect garbage from the contents of a keyring, replacing the old list with |
1141 | * a new one with the pointers all shuffled down. | 1187 | * a new one with the pointers all shuffled down. |
1142 | * | 1188 | * |
@@ -1161,7 +1207,8 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1161 | /* work out how many subscriptions we're keeping */ | 1207 | /* work out how many subscriptions we're keeping */ |
1162 | keep = 0; | 1208 | keep = 0; |
1163 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1209 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1164 | if (!key_is_dead(klist->keys[loop], limit)) | 1210 | if (!key_is_dead(rcu_deref_link_locked(klist, loop, keyring), |
1211 | limit)) | ||
1165 | keep++; | 1212 | keep++; |
1166 | 1213 | ||
1167 | if (keep == klist->nkeys) | 1214 | if (keep == klist->nkeys) |
@@ -1182,11 +1229,11 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1182 | */ | 1229 | */ |
1183 | keep = 0; | 1230 | keep = 0; |
1184 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 1231 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
1185 | key = klist->keys[loop]; | 1232 | key = rcu_deref_link_locked(klist, loop, keyring); |
1186 | if (!key_is_dead(key, limit)) { | 1233 | if (!key_is_dead(key, limit)) { |
1187 | if (keep >= max) | 1234 | if (keep >= max) |
1188 | goto discard_new; | 1235 | goto discard_new; |
1189 | new->keys[keep++] = key_get(key); | 1236 | RCU_INIT_POINTER(new->keys[keep++], key_get(key)); |
1190 | } | 1237 | } |
1191 | } | 1238 | } |
1192 | new->nkeys = keep; | 1239 | new->nkeys = keep; |
diff --git a/security/keys/permission.c b/security/keys/permission.c index c35b5229e3cd..57d96363d7f1 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
@@ -87,32 +87,29 @@ EXPORT_SYMBOL(key_task_permission); | |||
87 | * key_validate - Validate a key. | 87 | * key_validate - Validate a key. |
88 | * @key: The key to be validated. | 88 | * @key: The key to be validated. |
89 | * | 89 | * |
90 | * Check that a key is valid, returning 0 if the key is okay, -EKEYREVOKED if | 90 | * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the |
91 | * the key's type has been removed or if the key has been revoked or | 91 | * key is invalidated, -EKEYREVOKED if the key's type has been removed or if |
92 | * -EKEYEXPIRED if the key has expired. | 92 | * the key has been revoked or -EKEYEXPIRED if the key has expired. |
93 | */ | 93 | */ |
94 | int key_validate(struct key *key) | 94 | int key_validate(const struct key *key) |
95 | { | 95 | { |
96 | struct timespec now; | 96 | unsigned long flags = key->flags; |
97 | int ret = 0; | 97 | |
98 | 98 | if (flags & (1 << KEY_FLAG_INVALIDATED)) | |
99 | if (key) { | 99 | return -ENOKEY; |
100 | /* check it's still accessible */ | 100 | |
101 | ret = -EKEYREVOKED; | 101 | /* check it's still accessible */ |
102 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || | 102 | if (flags & ((1 << KEY_FLAG_REVOKED) | |
103 | test_bit(KEY_FLAG_DEAD, &key->flags)) | 103 | (1 << KEY_FLAG_DEAD))) |
104 | goto error; | 104 | return -EKEYREVOKED; |
105 | 105 | ||
106 | /* check it hasn't expired */ | 106 | /* check it hasn't expired */ |
107 | ret = 0; | 107 | if (key->expiry) { |
108 | if (key->expiry) { | 108 | struct timespec now = current_kernel_time(); |
109 | now = current_kernel_time(); | 109 | if (now.tv_sec >= key->expiry) |
110 | if (now.tv_sec >= key->expiry) | 110 | return -EKEYEXPIRED; |
111 | ret = -EKEYEXPIRED; | ||
112 | } | ||
113 | } | 111 | } |
114 | 112 | ||
115 | error: | 113 | return 0; |
116 | return ret; | ||
117 | } | 114 | } |
118 | EXPORT_SYMBOL(key_validate); | 115 | EXPORT_SYMBOL(key_validate); |
diff --git a/security/keys/proc.c b/security/keys/proc.c index 49bbc97943ad..30d1ddfd9cef 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -242,7 +242,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
242 | #define showflag(KEY, LETTER, FLAG) \ | 242 | #define showflag(KEY, LETTER, FLAG) \ |
243 | (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') | 243 | (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') |
244 | 244 | ||
245 | seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", | 245 | seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", |
246 | key->serial, | 246 | key->serial, |
247 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), | 247 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), |
248 | showflag(key, 'R', KEY_FLAG_REVOKED), | 248 | showflag(key, 'R', KEY_FLAG_REVOKED), |
@@ -250,6 +250,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
250 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), | 250 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), |
251 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), | 251 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), |
252 | showflag(key, 'N', KEY_FLAG_NEGATIVE), | 252 | showflag(key, 'N', KEY_FLAG_NEGATIVE), |
253 | showflag(key, 'i', KEY_FLAG_INVALIDATED), | ||
253 | atomic_read(&key->usage), | 254 | atomic_read(&key->usage), |
254 | xbuf, | 255 | xbuf, |
255 | key->perm, | 256 | key->perm, |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index be7ecb2018dd..e137fcd7042c 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -732,6 +732,8 @@ try_again: | |||
732 | if (ret < 0) | 732 | if (ret < 0) |
733 | goto invalid_key; | 733 | goto invalid_key; |
734 | 734 | ||
735 | key->last_used_at = current_kernel_time().tv_sec; | ||
736 | |||
735 | error: | 737 | error: |
736 | put_cred(cred); | 738 | put_cred(cred); |
737 | return key_ref; | 739 | return key_ref; |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 90c129b0102f..8d8d97dbb389 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
@@ -213,12 +213,15 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
213 | { | 213 | { |
214 | struct task_struct *tsk = current; | 214 | struct task_struct *tsk = current; |
215 | 215 | ||
216 | if (a->tsk) | 216 | /* |
217 | tsk = a->tsk; | 217 | * To keep stack sizes in check force programers to notice if they |
218 | if (tsk && tsk->pid) { | 218 | * start making this union too large! See struct lsm_network_audit |
219 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | 219 | * as an example of how to deal with large data. |
220 | audit_log_untrustedstring(ab, tsk->comm); | 220 | */ |
221 | } | 221 | BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2); |
222 | |||
223 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | ||
224 | audit_log_untrustedstring(ab, tsk->comm); | ||
222 | 225 | ||
223 | switch (a->type) { | 226 | switch (a->type) { |
224 | case LSM_AUDIT_DATA_NONE: | 227 | case LSM_AUDIT_DATA_NONE: |
diff --git a/security/security.c b/security/security.c index bf619ffc9a4d..5497a57fba01 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -701,11 +701,11 @@ int security_file_receive(struct file *file) | |||
701 | return security_ops->file_receive(file); | 701 | return security_ops->file_receive(file); |
702 | } | 702 | } |
703 | 703 | ||
704 | int security_dentry_open(struct file *file, const struct cred *cred) | 704 | int security_file_open(struct file *file, const struct cred *cred) |
705 | { | 705 | { |
706 | int ret; | 706 | int ret; |
707 | 707 | ||
708 | ret = security_ops->dentry_open(file, cred); | 708 | ret = security_ops->file_open(file, cred); |
709 | if (ret) | 709 | if (ret) |
710 | return ret; | 710 | return ret; |
711 | 711 | ||
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 8ee42b2a5f19..68d82daed257 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -65,14 +65,8 @@ struct avc_cache { | |||
65 | }; | 65 | }; |
66 | 66 | ||
67 | struct avc_callback_node { | 67 | struct avc_callback_node { |
68 | int (*callback) (u32 event, u32 ssid, u32 tsid, | 68 | int (*callback) (u32 event); |
69 | u16 tclass, u32 perms, | ||
70 | u32 *out_retained); | ||
71 | u32 events; | 69 | u32 events; |
72 | u32 ssid; | ||
73 | u32 tsid; | ||
74 | u16 tclass; | ||
75 | u32 perms; | ||
76 | struct avc_callback_node *next; | 70 | struct avc_callback_node *next; |
77 | }; | 71 | }; |
78 | 72 | ||
@@ -436,9 +430,9 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) | |||
436 | { | 430 | { |
437 | struct common_audit_data *ad = a; | 431 | struct common_audit_data *ad = a; |
438 | audit_log_format(ab, "avc: %s ", | 432 | audit_log_format(ab, "avc: %s ", |
439 | ad->selinux_audit_data->slad->denied ? "denied" : "granted"); | 433 | ad->selinux_audit_data->denied ? "denied" : "granted"); |
440 | avc_dump_av(ab, ad->selinux_audit_data->slad->tclass, | 434 | avc_dump_av(ab, ad->selinux_audit_data->tclass, |
441 | ad->selinux_audit_data->slad->audited); | 435 | ad->selinux_audit_data->audited); |
442 | audit_log_format(ab, " for "); | 436 | audit_log_format(ab, " for "); |
443 | } | 437 | } |
444 | 438 | ||
@@ -452,25 +446,23 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | |||
452 | { | 446 | { |
453 | struct common_audit_data *ad = a; | 447 | struct common_audit_data *ad = a; |
454 | audit_log_format(ab, " "); | 448 | audit_log_format(ab, " "); |
455 | avc_dump_query(ab, ad->selinux_audit_data->slad->ssid, | 449 | avc_dump_query(ab, ad->selinux_audit_data->ssid, |
456 | ad->selinux_audit_data->slad->tsid, | 450 | ad->selinux_audit_data->tsid, |
457 | ad->selinux_audit_data->slad->tclass); | 451 | ad->selinux_audit_data->tclass); |
458 | } | 452 | } |
459 | 453 | ||
460 | /* This is the slow part of avc audit with big stack footprint */ | 454 | /* This is the slow part of avc audit with big stack footprint */ |
461 | static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | 455 | noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, |
462 | u32 requested, u32 audited, u32 denied, | 456 | u32 requested, u32 audited, u32 denied, |
463 | struct common_audit_data *a, | 457 | struct common_audit_data *a, |
464 | unsigned flags) | 458 | unsigned flags) |
465 | { | 459 | { |
466 | struct common_audit_data stack_data; | 460 | struct common_audit_data stack_data; |
467 | struct selinux_audit_data sad = {0,}; | 461 | struct selinux_audit_data sad; |
468 | struct selinux_late_audit_data slad; | ||
469 | 462 | ||
470 | if (!a) { | 463 | if (!a) { |
471 | a = &stack_data; | 464 | a = &stack_data; |
472 | COMMON_AUDIT_DATA_INIT(a, NONE); | 465 | a->type = LSM_AUDIT_DATA_NONE; |
473 | a->selinux_audit_data = &sad; | ||
474 | } | 466 | } |
475 | 467 | ||
476 | /* | 468 | /* |
@@ -484,104 +476,34 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | |||
484 | (flags & MAY_NOT_BLOCK)) | 476 | (flags & MAY_NOT_BLOCK)) |
485 | return -ECHILD; | 477 | return -ECHILD; |
486 | 478 | ||
487 | slad.tclass = tclass; | 479 | sad.tclass = tclass; |
488 | slad.requested = requested; | 480 | sad.requested = requested; |
489 | slad.ssid = ssid; | 481 | sad.ssid = ssid; |
490 | slad.tsid = tsid; | 482 | sad.tsid = tsid; |
491 | slad.audited = audited; | 483 | sad.audited = audited; |
492 | slad.denied = denied; | 484 | sad.denied = denied; |
485 | |||
486 | a->selinux_audit_data = &sad; | ||
493 | 487 | ||
494 | a->selinux_audit_data->slad = &slad; | ||
495 | common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback); | 488 | common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback); |
496 | return 0; | 489 | return 0; |
497 | } | 490 | } |
498 | 491 | ||
499 | /** | 492 | /** |
500 | * avc_audit - Audit the granting or denial of permissions. | ||
501 | * @ssid: source security identifier | ||
502 | * @tsid: target security identifier | ||
503 | * @tclass: target security class | ||
504 | * @requested: requested permissions | ||
505 | * @avd: access vector decisions | ||
506 | * @result: result from avc_has_perm_noaudit | ||
507 | * @a: auxiliary audit data | ||
508 | * @flags: VFS walk flags | ||
509 | * | ||
510 | * Audit the granting or denial of permissions in accordance | ||
511 | * with the policy. This function is typically called by | ||
512 | * avc_has_perm() after a permission check, but can also be | ||
513 | * called directly by callers who use avc_has_perm_noaudit() | ||
514 | * in order to separate the permission check from the auditing. | ||
515 | * For example, this separation is useful when the permission check must | ||
516 | * be performed under a lock, to allow the lock to be released | ||
517 | * before calling the auditing code. | ||
518 | */ | ||
519 | inline int avc_audit(u32 ssid, u32 tsid, | ||
520 | u16 tclass, u32 requested, | ||
521 | struct av_decision *avd, int result, struct common_audit_data *a, | ||
522 | unsigned flags) | ||
523 | { | ||
524 | u32 denied, audited; | ||
525 | denied = requested & ~avd->allowed; | ||
526 | if (unlikely(denied)) { | ||
527 | audited = denied & avd->auditdeny; | ||
528 | /* | ||
529 | * a->selinux_audit_data->auditdeny is TRICKY! Setting a bit in | ||
530 | * this field means that ANY denials should NOT be audited if | ||
531 | * the policy contains an explicit dontaudit rule for that | ||
532 | * permission. Take notice that this is unrelated to the | ||
533 | * actual permissions that were denied. As an example lets | ||
534 | * assume: | ||
535 | * | ||
536 | * denied == READ | ||
537 | * avd.auditdeny & ACCESS == 0 (not set means explicit rule) | ||
538 | * selinux_audit_data->auditdeny & ACCESS == 1 | ||
539 | * | ||
540 | * We will NOT audit the denial even though the denied | ||
541 | * permission was READ and the auditdeny checks were for | ||
542 | * ACCESS | ||
543 | */ | ||
544 | if (a && | ||
545 | a->selinux_audit_data->auditdeny && | ||
546 | !(a->selinux_audit_data->auditdeny & avd->auditdeny)) | ||
547 | audited = 0; | ||
548 | } else if (result) | ||
549 | audited = denied = requested; | ||
550 | else | ||
551 | audited = requested & avd->auditallow; | ||
552 | if (likely(!audited)) | ||
553 | return 0; | ||
554 | |||
555 | return slow_avc_audit(ssid, tsid, tclass, | ||
556 | requested, audited, denied, | ||
557 | a, flags); | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * avc_add_callback - Register a callback for security events. | 493 | * avc_add_callback - Register a callback for security events. |
562 | * @callback: callback function | 494 | * @callback: callback function |
563 | * @events: security events | 495 | * @events: security events |
564 | * @ssid: source security identifier or %SECSID_WILD | ||
565 | * @tsid: target security identifier or %SECSID_WILD | ||
566 | * @tclass: target security class | ||
567 | * @perms: permissions | ||
568 | * | 496 | * |
569 | * Register a callback function for events in the set @events | 497 | * Register a callback function for events in the set @events. |
570 | * related to the SID pair (@ssid, @tsid) | 498 | * Returns %0 on success or -%ENOMEM if insufficient memory |
571 | * and the permissions @perms, interpreting | 499 | * exists to add the callback. |
572 | * @perms based on @tclass. Returns %0 on success or | ||
573 | * -%ENOMEM if insufficient memory exists to add the callback. | ||
574 | */ | 500 | */ |
575 | int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | 501 | int __init avc_add_callback(int (*callback)(u32 event), u32 events) |
576 | u16 tclass, u32 perms, | ||
577 | u32 *out_retained), | ||
578 | u32 events, u32 ssid, u32 tsid, | ||
579 | u16 tclass, u32 perms) | ||
580 | { | 502 | { |
581 | struct avc_callback_node *c; | 503 | struct avc_callback_node *c; |
582 | int rc = 0; | 504 | int rc = 0; |
583 | 505 | ||
584 | c = kmalloc(sizeof(*c), GFP_ATOMIC); | 506 | c = kmalloc(sizeof(*c), GFP_KERNEL); |
585 | if (!c) { | 507 | if (!c) { |
586 | rc = -ENOMEM; | 508 | rc = -ENOMEM; |
587 | goto out; | 509 | goto out; |
@@ -589,9 +511,6 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | |||
589 | 511 | ||
590 | c->callback = callback; | 512 | c->callback = callback; |
591 | c->events = events; | 513 | c->events = events; |
592 | c->ssid = ssid; | ||
593 | c->tsid = tsid; | ||
594 | c->perms = perms; | ||
595 | c->next = avc_callbacks; | 514 | c->next = avc_callbacks; |
596 | avc_callbacks = c; | 515 | avc_callbacks = c; |
597 | out: | 516 | out: |
@@ -731,8 +650,7 @@ int avc_ss_reset(u32 seqno) | |||
731 | 650 | ||
732 | for (c = avc_callbacks; c; c = c->next) { | 651 | for (c = avc_callbacks; c; c = c->next) { |
733 | if (c->events & AVC_CALLBACK_RESET) { | 652 | if (c->events & AVC_CALLBACK_RESET) { |
734 | tmprc = c->callback(AVC_CALLBACK_RESET, | 653 | tmprc = c->callback(AVC_CALLBACK_RESET); |
735 | 0, 0, 0, 0, NULL); | ||
736 | /* save the first error encountered for the return | 654 | /* save the first error encountered for the return |
737 | value and continue processing the callbacks */ | 655 | value and continue processing the callbacks */ |
738 | if (!rc) | 656 | if (!rc) |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d85b793c9321..fa2341b68331 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1420,16 +1420,13 @@ static int cred_has_capability(const struct cred *cred, | |||
1420 | int cap, int audit) | 1420 | int cap, int audit) |
1421 | { | 1421 | { |
1422 | struct common_audit_data ad; | 1422 | struct common_audit_data ad; |
1423 | struct selinux_audit_data sad = {0,}; | ||
1424 | struct av_decision avd; | 1423 | struct av_decision avd; |
1425 | u16 sclass; | 1424 | u16 sclass; |
1426 | u32 sid = cred_sid(cred); | 1425 | u32 sid = cred_sid(cred); |
1427 | u32 av = CAP_TO_MASK(cap); | 1426 | u32 av = CAP_TO_MASK(cap); |
1428 | int rc; | 1427 | int rc; |
1429 | 1428 | ||
1430 | COMMON_AUDIT_DATA_INIT(&ad, CAP); | 1429 | ad.type = LSM_AUDIT_DATA_CAP; |
1431 | ad.selinux_audit_data = &sad; | ||
1432 | ad.tsk = current; | ||
1433 | ad.u.cap = cap; | 1430 | ad.u.cap = cap; |
1434 | 1431 | ||
1435 | switch (CAP_TO_INDEX(cap)) { | 1432 | switch (CAP_TO_INDEX(cap)) { |
@@ -1488,20 +1485,6 @@ static int inode_has_perm(const struct cred *cred, | |||
1488 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); | 1485 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); |
1489 | } | 1486 | } |
1490 | 1487 | ||
1491 | static int inode_has_perm_noadp(const struct cred *cred, | ||
1492 | struct inode *inode, | ||
1493 | u32 perms, | ||
1494 | unsigned flags) | ||
1495 | { | ||
1496 | struct common_audit_data ad; | ||
1497 | struct selinux_audit_data sad = {0,}; | ||
1498 | |||
1499 | COMMON_AUDIT_DATA_INIT(&ad, INODE); | ||
1500 | ad.u.inode = inode; | ||
1501 | ad.selinux_audit_data = &sad; | ||
1502 | return inode_has_perm(cred, inode, perms, &ad, flags); | ||
1503 | } | ||
1504 | |||
1505 | /* Same as inode_has_perm, but pass explicit audit data containing | 1488 | /* Same as inode_has_perm, but pass explicit audit data containing |
1506 | the dentry to help the auditing code to more easily generate the | 1489 | the dentry to help the auditing code to more easily generate the |
1507 | pathname if needed. */ | 1490 | pathname if needed. */ |
@@ -1511,11 +1494,9 @@ static inline int dentry_has_perm(const struct cred *cred, | |||
1511 | { | 1494 | { |
1512 | struct inode *inode = dentry->d_inode; | 1495 | struct inode *inode = dentry->d_inode; |
1513 | struct common_audit_data ad; | 1496 | struct common_audit_data ad; |
1514 | struct selinux_audit_data sad = {0,}; | ||
1515 | 1497 | ||
1516 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 1498 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1517 | ad.u.dentry = dentry; | 1499 | ad.u.dentry = dentry; |
1518 | ad.selinux_audit_data = &sad; | ||
1519 | return inode_has_perm(cred, inode, av, &ad, 0); | 1500 | return inode_has_perm(cred, inode, av, &ad, 0); |
1520 | } | 1501 | } |
1521 | 1502 | ||
@@ -1528,11 +1509,9 @@ static inline int path_has_perm(const struct cred *cred, | |||
1528 | { | 1509 | { |
1529 | struct inode *inode = path->dentry->d_inode; | 1510 | struct inode *inode = path->dentry->d_inode; |
1530 | struct common_audit_data ad; | 1511 | struct common_audit_data ad; |
1531 | struct selinux_audit_data sad = {0,}; | ||
1532 | 1512 | ||
1533 | COMMON_AUDIT_DATA_INIT(&ad, PATH); | 1513 | ad.type = LSM_AUDIT_DATA_PATH; |
1534 | ad.u.path = *path; | 1514 | ad.u.path = *path; |
1535 | ad.selinux_audit_data = &sad; | ||
1536 | return inode_has_perm(cred, inode, av, &ad, 0); | 1515 | return inode_has_perm(cred, inode, av, &ad, 0); |
1537 | } | 1516 | } |
1538 | 1517 | ||
@@ -1551,13 +1530,11 @@ static int file_has_perm(const struct cred *cred, | |||
1551 | struct file_security_struct *fsec = file->f_security; | 1530 | struct file_security_struct *fsec = file->f_security; |
1552 | struct inode *inode = file->f_path.dentry->d_inode; | 1531 | struct inode *inode = file->f_path.dentry->d_inode; |
1553 | struct common_audit_data ad; | 1532 | struct common_audit_data ad; |
1554 | struct selinux_audit_data sad = {0,}; | ||
1555 | u32 sid = cred_sid(cred); | 1533 | u32 sid = cred_sid(cred); |
1556 | int rc; | 1534 | int rc; |
1557 | 1535 | ||
1558 | COMMON_AUDIT_DATA_INIT(&ad, PATH); | 1536 | ad.type = LSM_AUDIT_DATA_PATH; |
1559 | ad.u.path = file->f_path; | 1537 | ad.u.path = file->f_path; |
1560 | ad.selinux_audit_data = &sad; | ||
1561 | 1538 | ||
1562 | if (sid != fsec->sid) { | 1539 | if (sid != fsec->sid) { |
1563 | rc = avc_has_perm(sid, fsec->sid, | 1540 | rc = avc_has_perm(sid, fsec->sid, |
@@ -1587,7 +1564,6 @@ static int may_create(struct inode *dir, | |||
1587 | struct superblock_security_struct *sbsec; | 1564 | struct superblock_security_struct *sbsec; |
1588 | u32 sid, newsid; | 1565 | u32 sid, newsid; |
1589 | struct common_audit_data ad; | 1566 | struct common_audit_data ad; |
1590 | struct selinux_audit_data sad = {0,}; | ||
1591 | int rc; | 1567 | int rc; |
1592 | 1568 | ||
1593 | dsec = dir->i_security; | 1569 | dsec = dir->i_security; |
@@ -1596,9 +1572,8 @@ static int may_create(struct inode *dir, | |||
1596 | sid = tsec->sid; | 1572 | sid = tsec->sid; |
1597 | newsid = tsec->create_sid; | 1573 | newsid = tsec->create_sid; |
1598 | 1574 | ||
1599 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 1575 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1600 | ad.u.dentry = dentry; | 1576 | ad.u.dentry = dentry; |
1601 | ad.selinux_audit_data = &sad; | ||
1602 | 1577 | ||
1603 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, | 1578 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, |
1604 | DIR__ADD_NAME | DIR__SEARCH, | 1579 | DIR__ADD_NAME | DIR__SEARCH, |
@@ -1643,7 +1618,6 @@ static int may_link(struct inode *dir, | |||
1643 | { | 1618 | { |
1644 | struct inode_security_struct *dsec, *isec; | 1619 | struct inode_security_struct *dsec, *isec; |
1645 | struct common_audit_data ad; | 1620 | struct common_audit_data ad; |
1646 | struct selinux_audit_data sad = {0,}; | ||
1647 | u32 sid = current_sid(); | 1621 | u32 sid = current_sid(); |
1648 | u32 av; | 1622 | u32 av; |
1649 | int rc; | 1623 | int rc; |
@@ -1651,9 +1625,8 @@ static int may_link(struct inode *dir, | |||
1651 | dsec = dir->i_security; | 1625 | dsec = dir->i_security; |
1652 | isec = dentry->d_inode->i_security; | 1626 | isec = dentry->d_inode->i_security; |
1653 | 1627 | ||
1654 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 1628 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1655 | ad.u.dentry = dentry; | 1629 | ad.u.dentry = dentry; |
1656 | ad.selinux_audit_data = &sad; | ||
1657 | 1630 | ||
1658 | av = DIR__SEARCH; | 1631 | av = DIR__SEARCH; |
1659 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); | 1632 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); |
@@ -1688,7 +1661,6 @@ static inline int may_rename(struct inode *old_dir, | |||
1688 | { | 1661 | { |
1689 | struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; | 1662 | struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; |
1690 | struct common_audit_data ad; | 1663 | struct common_audit_data ad; |
1691 | struct selinux_audit_data sad = {0,}; | ||
1692 | u32 sid = current_sid(); | 1664 | u32 sid = current_sid(); |
1693 | u32 av; | 1665 | u32 av; |
1694 | int old_is_dir, new_is_dir; | 1666 | int old_is_dir, new_is_dir; |
@@ -1699,8 +1671,7 @@ static inline int may_rename(struct inode *old_dir, | |||
1699 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 1671 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); |
1700 | new_dsec = new_dir->i_security; | 1672 | new_dsec = new_dir->i_security; |
1701 | 1673 | ||
1702 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 1674 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1703 | ad.selinux_audit_data = &sad; | ||
1704 | 1675 | ||
1705 | ad.u.dentry = old_dentry; | 1676 | ad.u.dentry = old_dentry; |
1706 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, | 1677 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, |
@@ -1986,7 +1957,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
1986 | struct task_security_struct *new_tsec; | 1957 | struct task_security_struct *new_tsec; |
1987 | struct inode_security_struct *isec; | 1958 | struct inode_security_struct *isec; |
1988 | struct common_audit_data ad; | 1959 | struct common_audit_data ad; |
1989 | struct selinux_audit_data sad = {0,}; | ||
1990 | struct inode *inode = bprm->file->f_path.dentry->d_inode; | 1960 | struct inode *inode = bprm->file->f_path.dentry->d_inode; |
1991 | int rc; | 1961 | int rc; |
1992 | 1962 | ||
@@ -2016,6 +1986,13 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2016 | new_tsec->sid = old_tsec->exec_sid; | 1986 | new_tsec->sid = old_tsec->exec_sid; |
2017 | /* Reset exec SID on execve. */ | 1987 | /* Reset exec SID on execve. */ |
2018 | new_tsec->exec_sid = 0; | 1988 | new_tsec->exec_sid = 0; |
1989 | |||
1990 | /* | ||
1991 | * Minimize confusion: if no_new_privs and a transition is | ||
1992 | * explicitly requested, then fail the exec. | ||
1993 | */ | ||
1994 | if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) | ||
1995 | return -EPERM; | ||
2019 | } else { | 1996 | } else { |
2020 | /* Check for a default transition on this program. */ | 1997 | /* Check for a default transition on this program. */ |
2021 | rc = security_transition_sid(old_tsec->sid, isec->sid, | 1998 | rc = security_transition_sid(old_tsec->sid, isec->sid, |
@@ -2025,11 +2002,11 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2025 | return rc; | 2002 | return rc; |
2026 | } | 2003 | } |
2027 | 2004 | ||
2028 | COMMON_AUDIT_DATA_INIT(&ad, PATH); | 2005 | ad.type = LSM_AUDIT_DATA_PATH; |
2029 | ad.selinux_audit_data = &sad; | ||
2030 | ad.u.path = bprm->file->f_path; | 2006 | ad.u.path = bprm->file->f_path; |
2031 | 2007 | ||
2032 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | 2008 | if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) || |
2009 | (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) | ||
2033 | new_tsec->sid = old_tsec->sid; | 2010 | new_tsec->sid = old_tsec->sid; |
2034 | 2011 | ||
2035 | if (new_tsec->sid == old_tsec->sid) { | 2012 | if (new_tsec->sid == old_tsec->sid) { |
@@ -2115,8 +2092,6 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm) | |||
2115 | static inline void flush_unauthorized_files(const struct cred *cred, | 2092 | static inline void flush_unauthorized_files(const struct cred *cred, |
2116 | struct files_struct *files) | 2093 | struct files_struct *files) |
2117 | { | 2094 | { |
2118 | struct common_audit_data ad; | ||
2119 | struct selinux_audit_data sad = {0,}; | ||
2120 | struct file *file, *devnull = NULL; | 2095 | struct file *file, *devnull = NULL; |
2121 | struct tty_struct *tty; | 2096 | struct tty_struct *tty; |
2122 | struct fdtable *fdt; | 2097 | struct fdtable *fdt; |
@@ -2128,21 +2103,17 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2128 | spin_lock(&tty_files_lock); | 2103 | spin_lock(&tty_files_lock); |
2129 | if (!list_empty(&tty->tty_files)) { | 2104 | if (!list_empty(&tty->tty_files)) { |
2130 | struct tty_file_private *file_priv; | 2105 | struct tty_file_private *file_priv; |
2131 | struct inode *inode; | ||
2132 | 2106 | ||
2133 | /* Revalidate access to controlling tty. | 2107 | /* Revalidate access to controlling tty. |
2134 | Use inode_has_perm on the tty inode directly rather | 2108 | Use path_has_perm on the tty path directly rather |
2135 | than using file_has_perm, as this particular open | 2109 | than using file_has_perm, as this particular open |
2136 | file may belong to another process and we are only | 2110 | file may belong to another process and we are only |
2137 | interested in the inode-based check here. */ | 2111 | interested in the inode-based check here. */ |
2138 | file_priv = list_first_entry(&tty->tty_files, | 2112 | file_priv = list_first_entry(&tty->tty_files, |
2139 | struct tty_file_private, list); | 2113 | struct tty_file_private, list); |
2140 | file = file_priv->file; | 2114 | file = file_priv->file; |
2141 | inode = file->f_path.dentry->d_inode; | 2115 | if (path_has_perm(cred, &file->f_path, FILE__READ | FILE__WRITE)) |
2142 | if (inode_has_perm_noadp(cred, inode, | ||
2143 | FILE__READ | FILE__WRITE, 0)) { | ||
2144 | drop_tty = 1; | 2116 | drop_tty = 1; |
2145 | } | ||
2146 | } | 2117 | } |
2147 | spin_unlock(&tty_files_lock); | 2118 | spin_unlock(&tty_files_lock); |
2148 | tty_kref_put(tty); | 2119 | tty_kref_put(tty); |
@@ -2152,10 +2123,6 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2152 | no_tty(); | 2123 | no_tty(); |
2153 | 2124 | ||
2154 | /* Revalidate access to inherited open files. */ | 2125 | /* Revalidate access to inherited open files. */ |
2155 | |||
2156 | COMMON_AUDIT_DATA_INIT(&ad, INODE); | ||
2157 | ad.selinux_audit_data = &sad; | ||
2158 | |||
2159 | spin_lock(&files->file_lock); | 2126 | spin_lock(&files->file_lock); |
2160 | for (;;) { | 2127 | for (;;) { |
2161 | unsigned long set, i; | 2128 | unsigned long set, i; |
@@ -2492,7 +2459,6 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
2492 | { | 2459 | { |
2493 | const struct cred *cred = current_cred(); | 2460 | const struct cred *cred = current_cred(); |
2494 | struct common_audit_data ad; | 2461 | struct common_audit_data ad; |
2495 | struct selinux_audit_data sad = {0,}; | ||
2496 | int rc; | 2462 | int rc; |
2497 | 2463 | ||
2498 | rc = superblock_doinit(sb, data); | 2464 | rc = superblock_doinit(sb, data); |
@@ -2503,8 +2469,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
2503 | if (flags & MS_KERNMOUNT) | 2469 | if (flags & MS_KERNMOUNT) |
2504 | return 0; | 2470 | return 0; |
2505 | 2471 | ||
2506 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 2472 | ad.type = LSM_AUDIT_DATA_DENTRY; |
2507 | ad.selinux_audit_data = &sad; | ||
2508 | ad.u.dentry = sb->s_root; | 2473 | ad.u.dentry = sb->s_root; |
2509 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); | 2474 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); |
2510 | } | 2475 | } |
@@ -2513,10 +2478,8 @@ static int selinux_sb_statfs(struct dentry *dentry) | |||
2513 | { | 2478 | { |
2514 | const struct cred *cred = current_cred(); | 2479 | const struct cred *cred = current_cred(); |
2515 | struct common_audit_data ad; | 2480 | struct common_audit_data ad; |
2516 | struct selinux_audit_data sad = {0,}; | ||
2517 | 2481 | ||
2518 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 2482 | ad.type = LSM_AUDIT_DATA_DENTRY; |
2519 | ad.selinux_audit_data = &sad; | ||
2520 | ad.u.dentry = dentry->d_sb->s_root; | 2483 | ad.u.dentry = dentry->d_sb->s_root; |
2521 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); | 2484 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); |
2522 | } | 2485 | } |
@@ -2676,14 +2639,35 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na | |||
2676 | return dentry_has_perm(cred, dentry, FILE__READ); | 2639 | return dentry_has_perm(cred, dentry, FILE__READ); |
2677 | } | 2640 | } |
2678 | 2641 | ||
2642 | static noinline int audit_inode_permission(struct inode *inode, | ||
2643 | u32 perms, u32 audited, u32 denied, | ||
2644 | unsigned flags) | ||
2645 | { | ||
2646 | struct common_audit_data ad; | ||
2647 | struct inode_security_struct *isec = inode->i_security; | ||
2648 | int rc; | ||
2649 | |||
2650 | ad.type = LSM_AUDIT_DATA_INODE; | ||
2651 | ad.u.inode = inode; | ||
2652 | |||
2653 | rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms, | ||
2654 | audited, denied, &ad, flags); | ||
2655 | if (rc) | ||
2656 | return rc; | ||
2657 | return 0; | ||
2658 | } | ||
2659 | |||
2679 | static int selinux_inode_permission(struct inode *inode, int mask) | 2660 | static int selinux_inode_permission(struct inode *inode, int mask) |
2680 | { | 2661 | { |
2681 | const struct cred *cred = current_cred(); | 2662 | const struct cred *cred = current_cred(); |
2682 | struct common_audit_data ad; | ||
2683 | struct selinux_audit_data sad = {0,}; | ||
2684 | u32 perms; | 2663 | u32 perms; |
2685 | bool from_access; | 2664 | bool from_access; |
2686 | unsigned flags = mask & MAY_NOT_BLOCK; | 2665 | unsigned flags = mask & MAY_NOT_BLOCK; |
2666 | struct inode_security_struct *isec; | ||
2667 | u32 sid; | ||
2668 | struct av_decision avd; | ||
2669 | int rc, rc2; | ||
2670 | u32 audited, denied; | ||
2687 | 2671 | ||
2688 | from_access = mask & MAY_ACCESS; | 2672 | from_access = mask & MAY_ACCESS; |
2689 | mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); | 2673 | mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); |
@@ -2692,22 +2676,34 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
2692 | if (!mask) | 2676 | if (!mask) |
2693 | return 0; | 2677 | return 0; |
2694 | 2678 | ||
2695 | COMMON_AUDIT_DATA_INIT(&ad, INODE); | 2679 | validate_creds(cred); |
2696 | ad.selinux_audit_data = &sad; | ||
2697 | ad.u.inode = inode; | ||
2698 | 2680 | ||
2699 | if (from_access) | 2681 | if (unlikely(IS_PRIVATE(inode))) |
2700 | ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS; | 2682 | return 0; |
2701 | 2683 | ||
2702 | perms = file_mask_to_av(inode->i_mode, mask); | 2684 | perms = file_mask_to_av(inode->i_mode, mask); |
2703 | 2685 | ||
2704 | return inode_has_perm(cred, inode, perms, &ad, flags); | 2686 | sid = cred_sid(cred); |
2687 | isec = inode->i_security; | ||
2688 | |||
2689 | rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd); | ||
2690 | audited = avc_audit_required(perms, &avd, rc, | ||
2691 | from_access ? FILE__AUDIT_ACCESS : 0, | ||
2692 | &denied); | ||
2693 | if (likely(!audited)) | ||
2694 | return rc; | ||
2695 | |||
2696 | rc2 = audit_inode_permission(inode, perms, audited, denied, flags); | ||
2697 | if (rc2) | ||
2698 | return rc2; | ||
2699 | return rc; | ||
2705 | } | 2700 | } |
2706 | 2701 | ||
2707 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2702 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
2708 | { | 2703 | { |
2709 | const struct cred *cred = current_cred(); | 2704 | const struct cred *cred = current_cred(); |
2710 | unsigned int ia_valid = iattr->ia_valid; | 2705 | unsigned int ia_valid = iattr->ia_valid; |
2706 | __u32 av = FILE__WRITE; | ||
2711 | 2707 | ||
2712 | /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ | 2708 | /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ |
2713 | if (ia_valid & ATTR_FORCE) { | 2709 | if (ia_valid & ATTR_FORCE) { |
@@ -2721,7 +2717,10 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | |||
2721 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) | 2717 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) |
2722 | return dentry_has_perm(cred, dentry, FILE__SETATTR); | 2718 | return dentry_has_perm(cred, dentry, FILE__SETATTR); |
2723 | 2719 | ||
2724 | return dentry_has_perm(cred, dentry, FILE__WRITE); | 2720 | if (ia_valid & ATTR_SIZE) |
2721 | av |= FILE__OPEN; | ||
2722 | |||
2723 | return dentry_has_perm(cred, dentry, av); | ||
2725 | } | 2724 | } |
2726 | 2725 | ||
2727 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | 2726 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
@@ -2763,7 +2762,6 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2763 | struct inode_security_struct *isec = inode->i_security; | 2762 | struct inode_security_struct *isec = inode->i_security; |
2764 | struct superblock_security_struct *sbsec; | 2763 | struct superblock_security_struct *sbsec; |
2765 | struct common_audit_data ad; | 2764 | struct common_audit_data ad; |
2766 | struct selinux_audit_data sad = {0,}; | ||
2767 | u32 newsid, sid = current_sid(); | 2765 | u32 newsid, sid = current_sid(); |
2768 | int rc = 0; | 2766 | int rc = 0; |
2769 | 2767 | ||
@@ -2777,8 +2775,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2777 | if (!inode_owner_or_capable(inode)) | 2775 | if (!inode_owner_or_capable(inode)) |
2778 | return -EPERM; | 2776 | return -EPERM; |
2779 | 2777 | ||
2780 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 2778 | ad.type = LSM_AUDIT_DATA_DENTRY; |
2781 | ad.selinux_audit_data = &sad; | ||
2782 | ad.u.dentry = dentry; | 2779 | ad.u.dentry = dentry; |
2783 | 2780 | ||
2784 | rc = avc_has_perm(sid, isec->sid, isec->sclass, | 2781 | rc = avc_has_perm(sid, isec->sid, isec->sclass, |
@@ -2788,8 +2785,25 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2788 | 2785 | ||
2789 | rc = security_context_to_sid(value, size, &newsid); | 2786 | rc = security_context_to_sid(value, size, &newsid); |
2790 | if (rc == -EINVAL) { | 2787 | if (rc == -EINVAL) { |
2791 | if (!capable(CAP_MAC_ADMIN)) | 2788 | if (!capable(CAP_MAC_ADMIN)) { |
2789 | struct audit_buffer *ab; | ||
2790 | size_t audit_size; | ||
2791 | const char *str; | ||
2792 | |||
2793 | /* We strip a nul only if it is at the end, otherwise the | ||
2794 | * context contains a nul and we should audit that */ | ||
2795 | str = value; | ||
2796 | if (str[size - 1] == '\0') | ||
2797 | audit_size = size - 1; | ||
2798 | else | ||
2799 | audit_size = size; | ||
2800 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR); | ||
2801 | audit_log_format(ab, "op=setxattr invalid_context="); | ||
2802 | audit_log_n_untrustedstring(ab, value, audit_size); | ||
2803 | audit_log_end(ab); | ||
2804 | |||
2792 | return rc; | 2805 | return rc; |
2806 | } | ||
2793 | rc = security_context_to_sid_force(value, size, &newsid); | 2807 | rc = security_context_to_sid_force(value, size, &newsid); |
2794 | } | 2808 | } |
2795 | if (rc) | 2809 | if (rc) |
@@ -2969,7 +2983,7 @@ static int selinux_file_permission(struct file *file, int mask) | |||
2969 | 2983 | ||
2970 | if (sid == fsec->sid && fsec->isid == isec->sid && | 2984 | if (sid == fsec->sid && fsec->isid == isec->sid && |
2971 | fsec->pseqno == avc_policy_seqno()) | 2985 | fsec->pseqno == avc_policy_seqno()) |
2972 | /* No change since dentry_open check. */ | 2986 | /* No change since file_open check. */ |
2973 | return 0; | 2987 | return 0; |
2974 | 2988 | ||
2975 | return selinux_revalidate_file_permission(file, mask); | 2989 | return selinux_revalidate_file_permission(file, mask); |
@@ -3228,15 +3242,13 @@ static int selinux_file_receive(struct file *file) | |||
3228 | return file_has_perm(cred, file, file_to_av(file)); | 3242 | return file_has_perm(cred, file, file_to_av(file)); |
3229 | } | 3243 | } |
3230 | 3244 | ||
3231 | static int selinux_dentry_open(struct file *file, const struct cred *cred) | 3245 | static int selinux_file_open(struct file *file, const struct cred *cred) |
3232 | { | 3246 | { |
3233 | struct file_security_struct *fsec; | 3247 | struct file_security_struct *fsec; |
3234 | struct inode *inode; | ||
3235 | struct inode_security_struct *isec; | 3248 | struct inode_security_struct *isec; |
3236 | 3249 | ||
3237 | inode = file->f_path.dentry->d_inode; | ||
3238 | fsec = file->f_security; | 3250 | fsec = file->f_security; |
3239 | isec = inode->i_security; | 3251 | isec = file->f_path.dentry->d_inode->i_security; |
3240 | /* | 3252 | /* |
3241 | * Save inode label and policy sequence number | 3253 | * Save inode label and policy sequence number |
3242 | * at open-time so that selinux_file_permission | 3254 | * at open-time so that selinux_file_permission |
@@ -3254,7 +3266,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) | |||
3254 | * new inode label or new policy. | 3266 | * new inode label or new policy. |
3255 | * This check is not redundant - do not remove. | 3267 | * This check is not redundant - do not remove. |
3256 | */ | 3268 | */ |
3257 | return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0); | 3269 | return path_has_perm(cred, &file->f_path, open_file_to_av(file)); |
3258 | } | 3270 | } |
3259 | 3271 | ||
3260 | /* task security operations */ | 3272 | /* task security operations */ |
@@ -3373,12 +3385,10 @@ static int selinux_kernel_module_request(char *kmod_name) | |||
3373 | { | 3385 | { |
3374 | u32 sid; | 3386 | u32 sid; |
3375 | struct common_audit_data ad; | 3387 | struct common_audit_data ad; |
3376 | struct selinux_audit_data sad = {0,}; | ||
3377 | 3388 | ||
3378 | sid = task_sid(current); | 3389 | sid = task_sid(current); |
3379 | 3390 | ||
3380 | COMMON_AUDIT_DATA_INIT(&ad, KMOD); | 3391 | ad.type = LSM_AUDIT_DATA_KMOD; |
3381 | ad.selinux_audit_data = &sad; | ||
3382 | ad.u.kmod_name = kmod_name; | 3392 | ad.u.kmod_name = kmod_name; |
3383 | 3393 | ||
3384 | return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, | 3394 | return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, |
@@ -3751,15 +3761,13 @@ static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) | |||
3751 | { | 3761 | { |
3752 | struct sk_security_struct *sksec = sk->sk_security; | 3762 | struct sk_security_struct *sksec = sk->sk_security; |
3753 | struct common_audit_data ad; | 3763 | struct common_audit_data ad; |
3754 | struct selinux_audit_data sad = {0,}; | ||
3755 | struct lsm_network_audit net = {0,}; | 3764 | struct lsm_network_audit net = {0,}; |
3756 | u32 tsid = task_sid(task); | 3765 | u32 tsid = task_sid(task); |
3757 | 3766 | ||
3758 | if (sksec->sid == SECINITSID_KERNEL) | 3767 | if (sksec->sid == SECINITSID_KERNEL) |
3759 | return 0; | 3768 | return 0; |
3760 | 3769 | ||
3761 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3770 | ad.type = LSM_AUDIT_DATA_NET; |
3762 | ad.selinux_audit_data = &sad; | ||
3763 | ad.u.net = &net; | 3771 | ad.u.net = &net; |
3764 | ad.u.net->sk = sk; | 3772 | ad.u.net->sk = sk; |
3765 | 3773 | ||
@@ -3839,7 +3847,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3839 | char *addrp; | 3847 | char *addrp; |
3840 | struct sk_security_struct *sksec = sk->sk_security; | 3848 | struct sk_security_struct *sksec = sk->sk_security; |
3841 | struct common_audit_data ad; | 3849 | struct common_audit_data ad; |
3842 | struct selinux_audit_data sad = {0,}; | ||
3843 | struct lsm_network_audit net = {0,}; | 3850 | struct lsm_network_audit net = {0,}; |
3844 | struct sockaddr_in *addr4 = NULL; | 3851 | struct sockaddr_in *addr4 = NULL; |
3845 | struct sockaddr_in6 *addr6 = NULL; | 3852 | struct sockaddr_in6 *addr6 = NULL; |
@@ -3866,8 +3873,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3866 | snum, &sid); | 3873 | snum, &sid); |
3867 | if (err) | 3874 | if (err) |
3868 | goto out; | 3875 | goto out; |
3869 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3876 | ad.type = LSM_AUDIT_DATA_NET; |
3870 | ad.selinux_audit_data = &sad; | ||
3871 | ad.u.net = &net; | 3877 | ad.u.net = &net; |
3872 | ad.u.net->sport = htons(snum); | 3878 | ad.u.net->sport = htons(snum); |
3873 | ad.u.net->family = family; | 3879 | ad.u.net->family = family; |
@@ -3901,8 +3907,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3901 | if (err) | 3907 | if (err) |
3902 | goto out; | 3908 | goto out; |
3903 | 3909 | ||
3904 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3910 | ad.type = LSM_AUDIT_DATA_NET; |
3905 | ad.selinux_audit_data = &sad; | ||
3906 | ad.u.net = &net; | 3911 | ad.u.net = &net; |
3907 | ad.u.net->sport = htons(snum); | 3912 | ad.u.net->sport = htons(snum); |
3908 | ad.u.net->family = family; | 3913 | ad.u.net->family = family; |
@@ -3937,7 +3942,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3937 | if (sksec->sclass == SECCLASS_TCP_SOCKET || | 3942 | if (sksec->sclass == SECCLASS_TCP_SOCKET || |
3938 | sksec->sclass == SECCLASS_DCCP_SOCKET) { | 3943 | sksec->sclass == SECCLASS_DCCP_SOCKET) { |
3939 | struct common_audit_data ad; | 3944 | struct common_audit_data ad; |
3940 | struct selinux_audit_data sad = {0,}; | ||
3941 | struct lsm_network_audit net = {0,}; | 3945 | struct lsm_network_audit net = {0,}; |
3942 | struct sockaddr_in *addr4 = NULL; | 3946 | struct sockaddr_in *addr4 = NULL; |
3943 | struct sockaddr_in6 *addr6 = NULL; | 3947 | struct sockaddr_in6 *addr6 = NULL; |
@@ -3963,8 +3967,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3963 | perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ? | 3967 | perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ? |
3964 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; | 3968 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; |
3965 | 3969 | ||
3966 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3970 | ad.type = LSM_AUDIT_DATA_NET; |
3967 | ad.selinux_audit_data = &sad; | ||
3968 | ad.u.net = &net; | 3971 | ad.u.net = &net; |
3969 | ad.u.net->dport = htons(snum); | 3972 | ad.u.net->dport = htons(snum); |
3970 | ad.u.net->family = sk->sk_family; | 3973 | ad.u.net->family = sk->sk_family; |
@@ -4056,12 +4059,10 @@ static int selinux_socket_unix_stream_connect(struct sock *sock, | |||
4056 | struct sk_security_struct *sksec_other = other->sk_security; | 4059 | struct sk_security_struct *sksec_other = other->sk_security; |
4057 | struct sk_security_struct *sksec_new = newsk->sk_security; | 4060 | struct sk_security_struct *sksec_new = newsk->sk_security; |
4058 | struct common_audit_data ad; | 4061 | struct common_audit_data ad; |
4059 | struct selinux_audit_data sad = {0,}; | ||
4060 | struct lsm_network_audit net = {0,}; | 4062 | struct lsm_network_audit net = {0,}; |
4061 | int err; | 4063 | int err; |
4062 | 4064 | ||
4063 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4065 | ad.type = LSM_AUDIT_DATA_NET; |
4064 | ad.selinux_audit_data = &sad; | ||
4065 | ad.u.net = &net; | 4066 | ad.u.net = &net; |
4066 | ad.u.net->sk = other; | 4067 | ad.u.net->sk = other; |
4067 | 4068 | ||
@@ -4090,11 +4091,9 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
4090 | struct sk_security_struct *ssec = sock->sk->sk_security; | 4091 | struct sk_security_struct *ssec = sock->sk->sk_security; |
4091 | struct sk_security_struct *osec = other->sk->sk_security; | 4092 | struct sk_security_struct *osec = other->sk->sk_security; |
4092 | struct common_audit_data ad; | 4093 | struct common_audit_data ad; |
4093 | struct selinux_audit_data sad = {0,}; | ||
4094 | struct lsm_network_audit net = {0,}; | 4094 | struct lsm_network_audit net = {0,}; |
4095 | 4095 | ||
4096 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4096 | ad.type = LSM_AUDIT_DATA_NET; |
4097 | ad.selinux_audit_data = &sad; | ||
4098 | ad.u.net = &net; | 4097 | ad.u.net = &net; |
4099 | ad.u.net->sk = other->sk; | 4098 | ad.u.net->sk = other->sk; |
4100 | 4099 | ||
@@ -4132,12 +4131,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4132 | struct sk_security_struct *sksec = sk->sk_security; | 4131 | struct sk_security_struct *sksec = sk->sk_security; |
4133 | u32 sk_sid = sksec->sid; | 4132 | u32 sk_sid = sksec->sid; |
4134 | struct common_audit_data ad; | 4133 | struct common_audit_data ad; |
4135 | struct selinux_audit_data sad = {0,}; | ||
4136 | struct lsm_network_audit net = {0,}; | 4134 | struct lsm_network_audit net = {0,}; |
4137 | char *addrp; | 4135 | char *addrp; |
4138 | 4136 | ||
4139 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4137 | ad.type = LSM_AUDIT_DATA_NET; |
4140 | ad.selinux_audit_data = &sad; | ||
4141 | ad.u.net = &net; | 4138 | ad.u.net = &net; |
4142 | ad.u.net->netif = skb->skb_iif; | 4139 | ad.u.net->netif = skb->skb_iif; |
4143 | ad.u.net->family = family; | 4140 | ad.u.net->family = family; |
@@ -4167,7 +4164,6 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4167 | u16 family = sk->sk_family; | 4164 | u16 family = sk->sk_family; |
4168 | u32 sk_sid = sksec->sid; | 4165 | u32 sk_sid = sksec->sid; |
4169 | struct common_audit_data ad; | 4166 | struct common_audit_data ad; |
4170 | struct selinux_audit_data sad = {0,}; | ||
4171 | struct lsm_network_audit net = {0,}; | 4167 | struct lsm_network_audit net = {0,}; |
4172 | char *addrp; | 4168 | char *addrp; |
4173 | u8 secmark_active; | 4169 | u8 secmark_active; |
@@ -4192,8 +4188,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4192 | if (!secmark_active && !peerlbl_active) | 4188 | if (!secmark_active && !peerlbl_active) |
4193 | return 0; | 4189 | return 0; |
4194 | 4190 | ||
4195 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4191 | ad.type = LSM_AUDIT_DATA_NET; |
4196 | ad.selinux_audit_data = &sad; | ||
4197 | ad.u.net = &net; | 4192 | ad.u.net = &net; |
4198 | ad.u.net->netif = skb->skb_iif; | 4193 | ad.u.net->netif = skb->skb_iif; |
4199 | ad.u.net->family = family; | 4194 | ad.u.net->family = family; |
@@ -4531,7 +4526,6 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
4531 | char *addrp; | 4526 | char *addrp; |
4532 | u32 peer_sid; | 4527 | u32 peer_sid; |
4533 | struct common_audit_data ad; | 4528 | struct common_audit_data ad; |
4534 | struct selinux_audit_data sad = {0,}; | ||
4535 | struct lsm_network_audit net = {0,}; | 4529 | struct lsm_network_audit net = {0,}; |
4536 | u8 secmark_active; | 4530 | u8 secmark_active; |
4537 | u8 netlbl_active; | 4531 | u8 netlbl_active; |
@@ -4549,8 +4543,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
4549 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | 4543 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) |
4550 | return NF_DROP; | 4544 | return NF_DROP; |
4551 | 4545 | ||
4552 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4546 | ad.type = LSM_AUDIT_DATA_NET; |
4553 | ad.selinux_audit_data = &sad; | ||
4554 | ad.u.net = &net; | 4547 | ad.u.net = &net; |
4555 | ad.u.net->netif = ifindex; | 4548 | ad.u.net->netif = ifindex; |
4556 | ad.u.net->family = family; | 4549 | ad.u.net->family = family; |
@@ -4640,7 +4633,6 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
4640 | struct sock *sk = skb->sk; | 4633 | struct sock *sk = skb->sk; |
4641 | struct sk_security_struct *sksec; | 4634 | struct sk_security_struct *sksec; |
4642 | struct common_audit_data ad; | 4635 | struct common_audit_data ad; |
4643 | struct selinux_audit_data sad = {0,}; | ||
4644 | struct lsm_network_audit net = {0,}; | 4636 | struct lsm_network_audit net = {0,}; |
4645 | char *addrp; | 4637 | char *addrp; |
4646 | u8 proto; | 4638 | u8 proto; |
@@ -4649,8 +4641,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
4649 | return NF_ACCEPT; | 4641 | return NF_ACCEPT; |
4650 | sksec = sk->sk_security; | 4642 | sksec = sk->sk_security; |
4651 | 4643 | ||
4652 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4644 | ad.type = LSM_AUDIT_DATA_NET; |
4653 | ad.selinux_audit_data = &sad; | ||
4654 | ad.u.net = &net; | 4645 | ad.u.net = &net; |
4655 | ad.u.net->netif = ifindex; | 4646 | ad.u.net->netif = ifindex; |
4656 | ad.u.net->family = family; | 4647 | ad.u.net->family = family; |
@@ -4675,7 +4666,6 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4675 | u32 peer_sid; | 4666 | u32 peer_sid; |
4676 | struct sock *sk; | 4667 | struct sock *sk; |
4677 | struct common_audit_data ad; | 4668 | struct common_audit_data ad; |
4678 | struct selinux_audit_data sad = {0,}; | ||
4679 | struct lsm_network_audit net = {0,}; | 4669 | struct lsm_network_audit net = {0,}; |
4680 | char *addrp; | 4670 | char *addrp; |
4681 | u8 secmark_active; | 4671 | u8 secmark_active; |
@@ -4722,8 +4712,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4722 | secmark_perm = PACKET__SEND; | 4712 | secmark_perm = PACKET__SEND; |
4723 | } | 4713 | } |
4724 | 4714 | ||
4725 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4715 | ad.type = LSM_AUDIT_DATA_NET; |
4726 | ad.selinux_audit_data = &sad; | ||
4727 | ad.u.net = &net; | 4716 | ad.u.net = &net; |
4728 | ad.u.net->netif = ifindex; | 4717 | ad.u.net->netif = ifindex; |
4729 | ad.u.net->family = family; | 4718 | ad.u.net->family = family; |
@@ -4841,13 +4830,11 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, | |||
4841 | { | 4830 | { |
4842 | struct ipc_security_struct *isec; | 4831 | struct ipc_security_struct *isec; |
4843 | struct common_audit_data ad; | 4832 | struct common_audit_data ad; |
4844 | struct selinux_audit_data sad = {0,}; | ||
4845 | u32 sid = current_sid(); | 4833 | u32 sid = current_sid(); |
4846 | 4834 | ||
4847 | isec = ipc_perms->security; | 4835 | isec = ipc_perms->security; |
4848 | 4836 | ||
4849 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4837 | ad.type = LSM_AUDIT_DATA_IPC; |
4850 | ad.selinux_audit_data = &sad; | ||
4851 | ad.u.ipc_id = ipc_perms->key; | 4838 | ad.u.ipc_id = ipc_perms->key; |
4852 | 4839 | ||
4853 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); | 4840 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); |
@@ -4868,7 +4855,6 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) | |||
4868 | { | 4855 | { |
4869 | struct ipc_security_struct *isec; | 4856 | struct ipc_security_struct *isec; |
4870 | struct common_audit_data ad; | 4857 | struct common_audit_data ad; |
4871 | struct selinux_audit_data sad = {0,}; | ||
4872 | u32 sid = current_sid(); | 4858 | u32 sid = current_sid(); |
4873 | int rc; | 4859 | int rc; |
4874 | 4860 | ||
@@ -4878,8 +4864,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) | |||
4878 | 4864 | ||
4879 | isec = msq->q_perm.security; | 4865 | isec = msq->q_perm.security; |
4880 | 4866 | ||
4881 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4867 | ad.type = LSM_AUDIT_DATA_IPC; |
4882 | ad.selinux_audit_data = &sad; | ||
4883 | ad.u.ipc_id = msq->q_perm.key; | 4868 | ad.u.ipc_id = msq->q_perm.key; |
4884 | 4869 | ||
4885 | rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, | 4870 | rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, |
@@ -4900,13 +4885,11 @@ static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) | |||
4900 | { | 4885 | { |
4901 | struct ipc_security_struct *isec; | 4886 | struct ipc_security_struct *isec; |
4902 | struct common_audit_data ad; | 4887 | struct common_audit_data ad; |
4903 | struct selinux_audit_data sad = {0,}; | ||
4904 | u32 sid = current_sid(); | 4888 | u32 sid = current_sid(); |
4905 | 4889 | ||
4906 | isec = msq->q_perm.security; | 4890 | isec = msq->q_perm.security; |
4907 | 4891 | ||
4908 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4892 | ad.type = LSM_AUDIT_DATA_IPC; |
4909 | ad.selinux_audit_data = &sad; | ||
4910 | ad.u.ipc_id = msq->q_perm.key; | 4893 | ad.u.ipc_id = msq->q_perm.key; |
4911 | 4894 | ||
4912 | return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, | 4895 | return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, |
@@ -4946,7 +4929,6 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
4946 | struct ipc_security_struct *isec; | 4929 | struct ipc_security_struct *isec; |
4947 | struct msg_security_struct *msec; | 4930 | struct msg_security_struct *msec; |
4948 | struct common_audit_data ad; | 4931 | struct common_audit_data ad; |
4949 | struct selinux_audit_data sad = {0,}; | ||
4950 | u32 sid = current_sid(); | 4932 | u32 sid = current_sid(); |
4951 | int rc; | 4933 | int rc; |
4952 | 4934 | ||
@@ -4967,8 +4949,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
4967 | return rc; | 4949 | return rc; |
4968 | } | 4950 | } |
4969 | 4951 | ||
4970 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4952 | ad.type = LSM_AUDIT_DATA_IPC; |
4971 | ad.selinux_audit_data = &sad; | ||
4972 | ad.u.ipc_id = msq->q_perm.key; | 4953 | ad.u.ipc_id = msq->q_perm.key; |
4973 | 4954 | ||
4974 | /* Can this process write to the queue? */ | 4955 | /* Can this process write to the queue? */ |
@@ -4993,15 +4974,13 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, | |||
4993 | struct ipc_security_struct *isec; | 4974 | struct ipc_security_struct *isec; |
4994 | struct msg_security_struct *msec; | 4975 | struct msg_security_struct *msec; |
4995 | struct common_audit_data ad; | 4976 | struct common_audit_data ad; |
4996 | struct selinux_audit_data sad = {0,}; | ||
4997 | u32 sid = task_sid(target); | 4977 | u32 sid = task_sid(target); |
4998 | int rc; | 4978 | int rc; |
4999 | 4979 | ||
5000 | isec = msq->q_perm.security; | 4980 | isec = msq->q_perm.security; |
5001 | msec = msg->security; | 4981 | msec = msg->security; |
5002 | 4982 | ||
5003 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4983 | ad.type = LSM_AUDIT_DATA_IPC; |
5004 | ad.selinux_audit_data = &sad; | ||
5005 | ad.u.ipc_id = msq->q_perm.key; | 4984 | ad.u.ipc_id = msq->q_perm.key; |
5006 | 4985 | ||
5007 | rc = avc_has_perm(sid, isec->sid, | 4986 | rc = avc_has_perm(sid, isec->sid, |
@@ -5017,7 +4996,6 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) | |||
5017 | { | 4996 | { |
5018 | struct ipc_security_struct *isec; | 4997 | struct ipc_security_struct *isec; |
5019 | struct common_audit_data ad; | 4998 | struct common_audit_data ad; |
5020 | struct selinux_audit_data sad = {0,}; | ||
5021 | u32 sid = current_sid(); | 4999 | u32 sid = current_sid(); |
5022 | int rc; | 5000 | int rc; |
5023 | 5001 | ||
@@ -5027,8 +5005,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) | |||
5027 | 5005 | ||
5028 | isec = shp->shm_perm.security; | 5006 | isec = shp->shm_perm.security; |
5029 | 5007 | ||
5030 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 5008 | ad.type = LSM_AUDIT_DATA_IPC; |
5031 | ad.selinux_audit_data = &sad; | ||
5032 | ad.u.ipc_id = shp->shm_perm.key; | 5009 | ad.u.ipc_id = shp->shm_perm.key; |
5033 | 5010 | ||
5034 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, | 5011 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, |
@@ -5049,13 +5026,11 @@ static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) | |||
5049 | { | 5026 | { |
5050 | struct ipc_security_struct *isec; | 5027 | struct ipc_security_struct *isec; |
5051 | struct common_audit_data ad; | 5028 | struct common_audit_data ad; |
5052 | struct selinux_audit_data sad = {0,}; | ||
5053 | u32 sid = current_sid(); | 5029 | u32 sid = current_sid(); |
5054 | 5030 | ||
5055 | isec = shp->shm_perm.security; | 5031 | isec = shp->shm_perm.security; |
5056 | 5032 | ||
5057 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 5033 | ad.type = LSM_AUDIT_DATA_IPC; |
5058 | ad.selinux_audit_data = &sad; | ||
5059 | ad.u.ipc_id = shp->shm_perm.key; | 5034 | ad.u.ipc_id = shp->shm_perm.key; |
5060 | 5035 | ||
5061 | return avc_has_perm(sid, isec->sid, SECCLASS_SHM, | 5036 | return avc_has_perm(sid, isec->sid, SECCLASS_SHM, |
@@ -5113,7 +5088,6 @@ static int selinux_sem_alloc_security(struct sem_array *sma) | |||
5113 | { | 5088 | { |
5114 | struct ipc_security_struct *isec; | 5089 | struct ipc_security_struct *isec; |
5115 | struct common_audit_data ad; | 5090 | struct common_audit_data ad; |
5116 | struct selinux_audit_data sad = {0,}; | ||
5117 | u32 sid = current_sid(); | 5091 | u32 sid = current_sid(); |
5118 | int rc; | 5092 | int rc; |
5119 | 5093 | ||
@@ -5123,8 +5097,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) | |||
5123 | 5097 | ||
5124 | isec = sma->sem_perm.security; | 5098 | isec = sma->sem_perm.security; |
5125 | 5099 | ||
5126 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 5100 | ad.type = LSM_AUDIT_DATA_IPC; |
5127 | ad.selinux_audit_data = &sad; | ||
5128 | ad.u.ipc_id = sma->sem_perm.key; | 5101 | ad.u.ipc_id = sma->sem_perm.key; |
5129 | 5102 | ||
5130 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, | 5103 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, |
@@ -5145,13 +5118,11 @@ static int selinux_sem_associate(struct sem_array *sma, int semflg) | |||
5145 | { | 5118 | { |
5146 | struct ipc_security_struct *isec; | 5119 | struct ipc_security_struct *isec; |
5147 | struct common_audit_data ad; | 5120 | struct common_audit_data ad; |
5148 | struct selinux_audit_data sad = {0,}; | ||
5149 | u32 sid = current_sid(); | 5121 | u32 sid = current_sid(); |
5150 | 5122 | ||
5151 | isec = sma->sem_perm.security; | 5123 | isec = sma->sem_perm.security; |
5152 | 5124 | ||
5153 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 5125 | ad.type = LSM_AUDIT_DATA_IPC; |
5154 | ad.selinux_audit_data = &sad; | ||
5155 | ad.u.ipc_id = sma->sem_perm.key; | 5126 | ad.u.ipc_id = sma->sem_perm.key; |
5156 | 5127 | ||
5157 | return avc_has_perm(sid, isec->sid, SECCLASS_SEM, | 5128 | return avc_has_perm(sid, isec->sid, SECCLASS_SEM, |
@@ -5331,8 +5302,23 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5331 | } | 5302 | } |
5332 | error = security_context_to_sid(value, size, &sid); | 5303 | error = security_context_to_sid(value, size, &sid); |
5333 | if (error == -EINVAL && !strcmp(name, "fscreate")) { | 5304 | if (error == -EINVAL && !strcmp(name, "fscreate")) { |
5334 | if (!capable(CAP_MAC_ADMIN)) | 5305 | if (!capable(CAP_MAC_ADMIN)) { |
5306 | struct audit_buffer *ab; | ||
5307 | size_t audit_size; | ||
5308 | |||
5309 | /* We strip a nul only if it is at the end, otherwise the | ||
5310 | * context contains a nul and we should audit that */ | ||
5311 | if (str[size - 1] == '\0') | ||
5312 | audit_size = size - 1; | ||
5313 | else | ||
5314 | audit_size = size; | ||
5315 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR); | ||
5316 | audit_log_format(ab, "op=fscreate invalid_context="); | ||
5317 | audit_log_n_untrustedstring(ab, value, audit_size); | ||
5318 | audit_log_end(ab); | ||
5319 | |||
5335 | return error; | 5320 | return error; |
5321 | } | ||
5336 | error = security_context_to_sid_force(value, size, | 5322 | error = security_context_to_sid_force(value, size, |
5337 | &sid); | 5323 | &sid); |
5338 | } | 5324 | } |
@@ -5592,7 +5578,7 @@ static struct security_operations selinux_ops = { | |||
5592 | .file_send_sigiotask = selinux_file_send_sigiotask, | 5578 | .file_send_sigiotask = selinux_file_send_sigiotask, |
5593 | .file_receive = selinux_file_receive, | 5579 | .file_receive = selinux_file_receive, |
5594 | 5580 | ||
5595 | .dentry_open = selinux_dentry_open, | 5581 | .file_open = selinux_file_open, |
5596 | 5582 | ||
5597 | .task_create = selinux_task_create, | 5583 | .task_create = selinux_task_create, |
5598 | .cred_alloc_blank = selinux_cred_alloc_blank, | 5584 | .cred_alloc_blank = selinux_cred_alloc_blank, |
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 1931370233d7..92d0ab561db8 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -49,7 +49,7 @@ struct avc_cache_stats { | |||
49 | /* | 49 | /* |
50 | * We only need this data after we have decided to send an audit message. | 50 | * We only need this data after we have decided to send an audit message. |
51 | */ | 51 | */ |
52 | struct selinux_late_audit_data { | 52 | struct selinux_audit_data { |
53 | u32 ssid; | 53 | u32 ssid; |
54 | u32 tsid; | 54 | u32 tsid; |
55 | u16 tclass; | 55 | u16 tclass; |
@@ -60,28 +60,86 @@ struct selinux_late_audit_data { | |||
60 | }; | 60 | }; |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * We collect this at the beginning or during an selinux security operation | ||
64 | */ | ||
65 | struct selinux_audit_data { | ||
66 | /* | ||
67 | * auditdeny is a bit tricky and unintuitive. See the | ||
68 | * comments in avc.c for it's meaning and usage. | ||
69 | */ | ||
70 | u32 auditdeny; | ||
71 | struct selinux_late_audit_data *slad; | ||
72 | }; | ||
73 | |||
74 | /* | ||
75 | * AVC operations | 63 | * AVC operations |
76 | */ | 64 | */ |
77 | 65 | ||
78 | void __init avc_init(void); | 66 | void __init avc_init(void); |
79 | 67 | ||
80 | int avc_audit(u32 ssid, u32 tsid, | 68 | static inline u32 avc_audit_required(u32 requested, |
81 | u16 tclass, u32 requested, | 69 | struct av_decision *avd, |
82 | struct av_decision *avd, | 70 | int result, |
83 | int result, | 71 | u32 auditdeny, |
84 | struct common_audit_data *a, unsigned flags); | 72 | u32 *deniedp) |
73 | { | ||
74 | u32 denied, audited; | ||
75 | denied = requested & ~avd->allowed; | ||
76 | if (unlikely(denied)) { | ||
77 | audited = denied & avd->auditdeny; | ||
78 | /* | ||
79 | * auditdeny is TRICKY! Setting a bit in | ||
80 | * this field means that ANY denials should NOT be audited if | ||
81 | * the policy contains an explicit dontaudit rule for that | ||
82 | * permission. Take notice that this is unrelated to the | ||
83 | * actual permissions that were denied. As an example lets | ||
84 | * assume: | ||
85 | * | ||
86 | * denied == READ | ||
87 | * avd.auditdeny & ACCESS == 0 (not set means explicit rule) | ||
88 | * auditdeny & ACCESS == 1 | ||
89 | * | ||
90 | * We will NOT audit the denial even though the denied | ||
91 | * permission was READ and the auditdeny checks were for | ||
92 | * ACCESS | ||
93 | */ | ||
94 | if (auditdeny && !(auditdeny & avd->auditdeny)) | ||
95 | audited = 0; | ||
96 | } else if (result) | ||
97 | audited = denied = requested; | ||
98 | else | ||
99 | audited = requested & avd->auditallow; | ||
100 | *deniedp = denied; | ||
101 | return audited; | ||
102 | } | ||
103 | |||
104 | int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | ||
105 | u32 requested, u32 audited, u32 denied, | ||
106 | struct common_audit_data *a, | ||
107 | unsigned flags); | ||
108 | |||
109 | /** | ||
110 | * avc_audit - Audit the granting or denial of permissions. | ||
111 | * @ssid: source security identifier | ||
112 | * @tsid: target security identifier | ||
113 | * @tclass: target security class | ||
114 | * @requested: requested permissions | ||
115 | * @avd: access vector decisions | ||
116 | * @result: result from avc_has_perm_noaudit | ||
117 | * @a: auxiliary audit data | ||
118 | * @flags: VFS walk flags | ||
119 | * | ||
120 | * Audit the granting or denial of permissions in accordance | ||
121 | * with the policy. This function is typically called by | ||
122 | * avc_has_perm() after a permission check, but can also be | ||
123 | * called directly by callers who use avc_has_perm_noaudit() | ||
124 | * in order to separate the permission check from the auditing. | ||
125 | * For example, this separation is useful when the permission check must | ||
126 | * be performed under a lock, to allow the lock to be released | ||
127 | * before calling the auditing code. | ||
128 | */ | ||
129 | static inline int avc_audit(u32 ssid, u32 tsid, | ||
130 | u16 tclass, u32 requested, | ||
131 | struct av_decision *avd, | ||
132 | int result, | ||
133 | struct common_audit_data *a, unsigned flags) | ||
134 | { | ||
135 | u32 audited, denied; | ||
136 | audited = avc_audit_required(requested, avd, result, 0, &denied); | ||
137 | if (likely(!audited)) | ||
138 | return 0; | ||
139 | return slow_avc_audit(ssid, tsid, tclass, | ||
140 | requested, audited, denied, | ||
141 | a, flags); | ||
142 | } | ||
85 | 143 | ||
86 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | 144 | #define AVC_STRICT 1 /* Ignore permissive mode. */ |
87 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 145 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
@@ -112,11 +170,7 @@ u32 avc_policy_seqno(void); | |||
112 | #define AVC_CALLBACK_AUDITDENY_ENABLE 64 | 170 | #define AVC_CALLBACK_AUDITDENY_ENABLE 64 |
113 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 | 171 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 |
114 | 172 | ||
115 | int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | 173 | int avc_add_callback(int (*callback)(u32 event), u32 events); |
116 | u16 tclass, u32 perms, | ||
117 | u32 *out_retained), | ||
118 | u32 events, u32 ssid, u32 tsid, | ||
119 | u16 tclass, u32 perms); | ||
120 | 174 | ||
121 | /* Exported to selinuxfs */ | 175 | /* Exported to selinuxfs */ |
122 | int avc_get_hash_stats(char *page); | 176 | int avc_get_hash_stats(char *page); |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index d871e8ad2103..dde2005407aa 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -31,13 +31,15 @@ | |||
31 | #define POLICYDB_VERSION_BOUNDARY 24 | 31 | #define POLICYDB_VERSION_BOUNDARY 24 |
32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 | 32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 |
33 | #define POLICYDB_VERSION_ROLETRANS 26 | 33 | #define POLICYDB_VERSION_ROLETRANS 26 |
34 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 | ||
35 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 | ||
34 | 36 | ||
35 | /* Range of policy versions we understand*/ | 37 | /* Range of policy versions we understand*/ |
36 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 38 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
37 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 39 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
38 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 40 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
39 | #else | 41 | #else |
40 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS | 42 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE |
41 | #endif | 43 | #endif |
42 | 44 | ||
43 | /* Mask for just the mount related flags */ | 45 | /* Mask for just the mount related flags */ |
diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 326f22cbe405..47a49d1a6f6a 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c | |||
@@ -252,8 +252,7 @@ static void sel_netif_flush(void) | |||
252 | spin_unlock_bh(&sel_netif_lock); | 252 | spin_unlock_bh(&sel_netif_lock); |
253 | } | 253 | } |
254 | 254 | ||
255 | static int sel_netif_avc_callback(u32 event, u32 ssid, u32 tsid, | 255 | static int sel_netif_avc_callback(u32 event) |
256 | u16 class, u32 perms, u32 *retained) | ||
257 | { | 256 | { |
258 | if (event == AVC_CALLBACK_RESET) { | 257 | if (event == AVC_CALLBACK_RESET) { |
259 | sel_netif_flush(); | 258 | sel_netif_flush(); |
@@ -292,8 +291,7 @@ static __init int sel_netif_init(void) | |||
292 | 291 | ||
293 | register_netdevice_notifier(&sel_netif_netdev_notifier); | 292 | register_netdevice_notifier(&sel_netif_netdev_notifier); |
294 | 293 | ||
295 | err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET, | 294 | err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET); |
296 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | ||
297 | if (err) | 295 | if (err) |
298 | panic("avc_add_callback() failed, error %d\n", err); | 296 | panic("avc_add_callback() failed, error %d\n", err); |
299 | 297 | ||
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 86365857c088..28f911cdd7c7 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
@@ -297,8 +297,7 @@ static void sel_netnode_flush(void) | |||
297 | spin_unlock_bh(&sel_netnode_lock); | 297 | spin_unlock_bh(&sel_netnode_lock); |
298 | } | 298 | } |
299 | 299 | ||
300 | static int sel_netnode_avc_callback(u32 event, u32 ssid, u32 tsid, | 300 | static int sel_netnode_avc_callback(u32 event) |
301 | u16 class, u32 perms, u32 *retained) | ||
302 | { | 301 | { |
303 | if (event == AVC_CALLBACK_RESET) { | 302 | if (event == AVC_CALLBACK_RESET) { |
304 | sel_netnode_flush(); | 303 | sel_netnode_flush(); |
@@ -320,8 +319,7 @@ static __init int sel_netnode_init(void) | |||
320 | sel_netnode_hash[iter].size = 0; | 319 | sel_netnode_hash[iter].size = 0; |
321 | } | 320 | } |
322 | 321 | ||
323 | ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET, | 322 | ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET); |
324 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | ||
325 | if (ret != 0) | 323 | if (ret != 0) |
326 | panic("avc_add_callback() failed, error %d\n", ret); | 324 | panic("avc_add_callback() failed, error %d\n", ret); |
327 | 325 | ||
diff --git a/security/selinux/netport.c b/security/selinux/netport.c index 7b9eb1faf68b..d35379781c2c 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c | |||
@@ -234,8 +234,7 @@ static void sel_netport_flush(void) | |||
234 | spin_unlock_bh(&sel_netport_lock); | 234 | spin_unlock_bh(&sel_netport_lock); |
235 | } | 235 | } |
236 | 236 | ||
237 | static int sel_netport_avc_callback(u32 event, u32 ssid, u32 tsid, | 237 | static int sel_netport_avc_callback(u32 event) |
238 | u16 class, u32 perms, u32 *retained) | ||
239 | { | 238 | { |
240 | if (event == AVC_CALLBACK_RESET) { | 239 | if (event == AVC_CALLBACK_RESET) { |
241 | sel_netport_flush(); | 240 | sel_netport_flush(); |
@@ -257,8 +256,7 @@ static __init int sel_netport_init(void) | |||
257 | sel_netport_hash[iter].size = 0; | 256 | sel_netport_hash[iter].size = 0; |
258 | } | 257 | } |
259 | 258 | ||
260 | ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET, | 259 | ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET); |
261 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | ||
262 | if (ret != 0) | 260 | if (ret != 0) |
263 | panic("avc_add_callback() failed, error %d\n", ret); | 261 | panic("avc_add_callback() failed, error %d\n", ret); |
264 | 262 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d7018bfa1f00..4e93f9ef970b 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -496,6 +496,7 @@ static const struct file_operations sel_policy_ops = { | |||
496 | .read = sel_read_policy, | 496 | .read = sel_read_policy, |
497 | .mmap = sel_mmap_policy, | 497 | .mmap = sel_mmap_policy, |
498 | .release = sel_release_policy, | 498 | .release = sel_release_policy, |
499 | .llseek = generic_file_llseek, | ||
499 | }; | 500 | }; |
500 | 501 | ||
501 | static ssize_t sel_write_load(struct file *file, const char __user *buf, | 502 | static ssize_t sel_write_load(struct file *file, const char __user *buf, |
@@ -1232,6 +1233,7 @@ static int sel_make_bools(void) | |||
1232 | kfree(bool_pending_names[i]); | 1233 | kfree(bool_pending_names[i]); |
1233 | kfree(bool_pending_names); | 1234 | kfree(bool_pending_names); |
1234 | kfree(bool_pending_values); | 1235 | kfree(bool_pending_values); |
1236 | bool_num = 0; | ||
1235 | bool_pending_names = NULL; | 1237 | bool_pending_names = NULL; |
1236 | bool_pending_values = NULL; | 1238 | bool_pending_values = NULL; |
1237 | 1239 | ||
@@ -1532,11 +1534,6 @@ static int sel_make_initcon_files(struct dentry *dir) | |||
1532 | return 0; | 1534 | return 0; |
1533 | } | 1535 | } |
1534 | 1536 | ||
1535 | static inline unsigned int sel_div(unsigned long a, unsigned long b) | ||
1536 | { | ||
1537 | return a / b - (a % b < 0); | ||
1538 | } | ||
1539 | |||
1540 | static inline unsigned long sel_class_to_ino(u16 class) | 1537 | static inline unsigned long sel_class_to_ino(u16 class) |
1541 | { | 1538 | { |
1542 | return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET; | 1539 | return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET; |
@@ -1544,7 +1541,7 @@ static inline unsigned long sel_class_to_ino(u16 class) | |||
1544 | 1541 | ||
1545 | static inline u16 sel_ino_to_class(unsigned long ino) | 1542 | static inline u16 sel_ino_to_class(unsigned long ino) |
1546 | { | 1543 | { |
1547 | return sel_div(ino & SEL_INO_MASK, SEL_VEC_MAX + 1); | 1544 | return (ino & SEL_INO_MASK) / (SEL_VEC_MAX + 1); |
1548 | } | 1545 | } |
1549 | 1546 | ||
1550 | static inline unsigned long sel_perm_to_ino(u16 class, u32 perm) | 1547 | static inline unsigned long sel_perm_to_ino(u16 class, u32 perm) |
@@ -1831,7 +1828,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1831 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1828 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1832 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1829 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1833 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, | 1830 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, |
1834 | [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR}, | 1831 | [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO}, |
1835 | /* last one */ {""} | 1832 | /* last one */ {""} |
1836 | }; | 1833 | }; |
1837 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1834 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); |
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index 45e8fb0515f8..212e3479a0d9 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h | |||
@@ -74,6 +74,26 @@ out: | |||
74 | return rc; | 74 | return rc; |
75 | } | 75 | } |
76 | 76 | ||
77 | /* | ||
78 | * Sets both levels in the MLS range of 'dst' to the high level of 'src'. | ||
79 | */ | ||
80 | static inline int mls_context_cpy_high(struct context *dst, struct context *src) | ||
81 | { | ||
82 | int rc; | ||
83 | |||
84 | dst->range.level[0].sens = src->range.level[1].sens; | ||
85 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[1].cat); | ||
86 | if (rc) | ||
87 | goto out; | ||
88 | |||
89 | dst->range.level[1].sens = src->range.level[1].sens; | ||
90 | rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat); | ||
91 | if (rc) | ||
92 | ebitmap_destroy(&dst->range.level[0].cat); | ||
93 | out: | ||
94 | return rc; | ||
95 | } | ||
96 | |||
77 | static inline int mls_context_cmp(struct context *c1, struct context *c2) | 97 | static inline int mls_context_cmp(struct context *c1, struct context *c2) |
78 | { | 98 | { |
79 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && | 99 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index fbf9c5816c71..40de8d3f208e 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
@@ -517,6 +517,8 @@ int mls_compute_sid(struct context *scontext, | |||
517 | { | 517 | { |
518 | struct range_trans rtr; | 518 | struct range_trans rtr; |
519 | struct mls_range *r; | 519 | struct mls_range *r; |
520 | struct class_datum *cladatum; | ||
521 | int default_range = 0; | ||
520 | 522 | ||
521 | if (!policydb.mls_enabled) | 523 | if (!policydb.mls_enabled) |
522 | return 0; | 524 | return 0; |
@@ -530,6 +532,28 @@ int mls_compute_sid(struct context *scontext, | |||
530 | r = hashtab_search(policydb.range_tr, &rtr); | 532 | r = hashtab_search(policydb.range_tr, &rtr); |
531 | if (r) | 533 | if (r) |
532 | return mls_range_set(newcontext, r); | 534 | return mls_range_set(newcontext, r); |
535 | |||
536 | if (tclass && tclass <= policydb.p_classes.nprim) { | ||
537 | cladatum = policydb.class_val_to_struct[tclass - 1]; | ||
538 | if (cladatum) | ||
539 | default_range = cladatum->default_range; | ||
540 | } | ||
541 | |||
542 | switch (default_range) { | ||
543 | case DEFAULT_SOURCE_LOW: | ||
544 | return mls_context_cpy_low(newcontext, scontext); | ||
545 | case DEFAULT_SOURCE_HIGH: | ||
546 | return mls_context_cpy_high(newcontext, scontext); | ||
547 | case DEFAULT_SOURCE_LOW_HIGH: | ||
548 | return mls_context_cpy(newcontext, scontext); | ||
549 | case DEFAULT_TARGET_LOW: | ||
550 | return mls_context_cpy_low(newcontext, tcontext); | ||
551 | case DEFAULT_TARGET_HIGH: | ||
552 | return mls_context_cpy_high(newcontext, tcontext); | ||
553 | case DEFAULT_TARGET_LOW_HIGH: | ||
554 | return mls_context_cpy(newcontext, tcontext); | ||
555 | } | ||
556 | |||
533 | /* Fallthrough */ | 557 | /* Fallthrough */ |
534 | case AVTAB_CHANGE: | 558 | case AVTAB_CHANGE: |
535 | if ((tclass == policydb.process_class) || (sock == true)) | 559 | if ((tclass == policydb.process_class) || (sock == true)) |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index a7f61d52f05c..9cd9b7c661ec 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -133,6 +133,16 @@ static struct policydb_compat_info policydb_compat[] = { | |||
133 | .sym_num = SYM_NUM, | 133 | .sym_num = SYM_NUM, |
134 | .ocon_num = OCON_NUM, | 134 | .ocon_num = OCON_NUM, |
135 | }, | 135 | }, |
136 | { | ||
137 | .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, | ||
138 | .sym_num = SYM_NUM, | ||
139 | .ocon_num = OCON_NUM, | ||
140 | }, | ||
141 | { | ||
142 | .version = POLICYDB_VERSION_DEFAULT_TYPE, | ||
143 | .sym_num = SYM_NUM, | ||
144 | .ocon_num = OCON_NUM, | ||
145 | }, | ||
136 | }; | 146 | }; |
137 | 147 | ||
138 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 148 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
@@ -1306,6 +1316,23 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1306 | goto bad; | 1316 | goto bad; |
1307 | } | 1317 | } |
1308 | 1318 | ||
1319 | if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) { | ||
1320 | rc = next_entry(buf, fp, sizeof(u32) * 3); | ||
1321 | if (rc) | ||
1322 | goto bad; | ||
1323 | |||
1324 | cladatum->default_user = le32_to_cpu(buf[0]); | ||
1325 | cladatum->default_role = le32_to_cpu(buf[1]); | ||
1326 | cladatum->default_range = le32_to_cpu(buf[2]); | ||
1327 | } | ||
1328 | |||
1329 | if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) { | ||
1330 | rc = next_entry(buf, fp, sizeof(u32) * 1); | ||
1331 | if (rc) | ||
1332 | goto bad; | ||
1333 | cladatum->default_type = le32_to_cpu(buf[0]); | ||
1334 | } | ||
1335 | |||
1309 | rc = hashtab_insert(h, key, cladatum); | 1336 | rc = hashtab_insert(h, key, cladatum); |
1310 | if (rc) | 1337 | if (rc) |
1311 | goto bad; | 1338 | goto bad; |
@@ -2832,6 +2859,23 @@ static int class_write(void *vkey, void *datum, void *ptr) | |||
2832 | if (rc) | 2859 | if (rc) |
2833 | return rc; | 2860 | return rc; |
2834 | 2861 | ||
2862 | if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) { | ||
2863 | buf[0] = cpu_to_le32(cladatum->default_user); | ||
2864 | buf[1] = cpu_to_le32(cladatum->default_role); | ||
2865 | buf[2] = cpu_to_le32(cladatum->default_range); | ||
2866 | |||
2867 | rc = put_entry(buf, sizeof(uint32_t), 3, fp); | ||
2868 | if (rc) | ||
2869 | return rc; | ||
2870 | } | ||
2871 | |||
2872 | if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) { | ||
2873 | buf[0] = cpu_to_le32(cladatum->default_type); | ||
2874 | rc = put_entry(buf, sizeof(uint32_t), 1, fp); | ||
2875 | if (rc) | ||
2876 | return rc; | ||
2877 | } | ||
2878 | |||
2835 | return 0; | 2879 | return 0; |
2836 | } | 2880 | } |
2837 | 2881 | ||
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index b846c0387180..da637471d4ce 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -60,6 +60,20 @@ struct class_datum { | |||
60 | struct symtab permissions; /* class-specific permission symbol table */ | 60 | struct symtab permissions; /* class-specific permission symbol table */ |
61 | struct constraint_node *constraints; /* constraints on class permissions */ | 61 | struct constraint_node *constraints; /* constraints on class permissions */ |
62 | struct constraint_node *validatetrans; /* special transition rules */ | 62 | struct constraint_node *validatetrans; /* special transition rules */ |
63 | /* Options how a new object user, role, and type should be decided */ | ||
64 | #define DEFAULT_SOURCE 1 | ||
65 | #define DEFAULT_TARGET 2 | ||
66 | char default_user; | ||
67 | char default_role; | ||
68 | char default_type; | ||
69 | /* Options how a new object range should be decided */ | ||
70 | #define DEFAULT_SOURCE_LOW 1 | ||
71 | #define DEFAULT_SOURCE_HIGH 2 | ||
72 | #define DEFAULT_SOURCE_LOW_HIGH 3 | ||
73 | #define DEFAULT_TARGET_LOW 4 | ||
74 | #define DEFAULT_TARGET_HIGH 5 | ||
75 | #define DEFAULT_TARGET_LOW_HIGH 6 | ||
76 | char default_range; | ||
63 | }; | 77 | }; |
64 | 78 | ||
65 | /* Role attributes */ | 79 | /* Role attributes */ |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 185f849a26f6..4321b8fc8863 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -1018,9 +1018,11 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 | |||
1018 | 1018 | ||
1019 | if (context->len) { | 1019 | if (context->len) { |
1020 | *scontext_len = context->len; | 1020 | *scontext_len = context->len; |
1021 | *scontext = kstrdup(context->str, GFP_ATOMIC); | 1021 | if (scontext) { |
1022 | if (!(*scontext)) | 1022 | *scontext = kstrdup(context->str, GFP_ATOMIC); |
1023 | return -ENOMEM; | 1023 | if (!(*scontext)) |
1024 | return -ENOMEM; | ||
1025 | } | ||
1024 | return 0; | 1026 | return 0; |
1025 | } | 1027 | } |
1026 | 1028 | ||
@@ -1389,6 +1391,7 @@ static int security_compute_sid(u32 ssid, | |||
1389 | u32 *out_sid, | 1391 | u32 *out_sid, |
1390 | bool kern) | 1392 | bool kern) |
1391 | { | 1393 | { |
1394 | struct class_datum *cladatum = NULL; | ||
1392 | struct context *scontext = NULL, *tcontext = NULL, newcontext; | 1395 | struct context *scontext = NULL, *tcontext = NULL, newcontext; |
1393 | struct role_trans *roletr = NULL; | 1396 | struct role_trans *roletr = NULL; |
1394 | struct avtab_key avkey; | 1397 | struct avtab_key avkey; |
@@ -1437,12 +1440,20 @@ static int security_compute_sid(u32 ssid, | |||
1437 | goto out_unlock; | 1440 | goto out_unlock; |
1438 | } | 1441 | } |
1439 | 1442 | ||
1443 | if (tclass && tclass <= policydb.p_classes.nprim) | ||
1444 | cladatum = policydb.class_val_to_struct[tclass - 1]; | ||
1445 | |||
1440 | /* Set the user identity. */ | 1446 | /* Set the user identity. */ |
1441 | switch (specified) { | 1447 | switch (specified) { |
1442 | case AVTAB_TRANSITION: | 1448 | case AVTAB_TRANSITION: |
1443 | case AVTAB_CHANGE: | 1449 | case AVTAB_CHANGE: |
1444 | /* Use the process user identity. */ | 1450 | if (cladatum && cladatum->default_user == DEFAULT_TARGET) { |
1445 | newcontext.user = scontext->user; | 1451 | newcontext.user = tcontext->user; |
1452 | } else { | ||
1453 | /* notice this gets both DEFAULT_SOURCE and unset */ | ||
1454 | /* Use the process user identity. */ | ||
1455 | newcontext.user = scontext->user; | ||
1456 | } | ||
1446 | break; | 1457 | break; |
1447 | case AVTAB_MEMBER: | 1458 | case AVTAB_MEMBER: |
1448 | /* Use the related object owner. */ | 1459 | /* Use the related object owner. */ |
@@ -1450,16 +1461,31 @@ static int security_compute_sid(u32 ssid, | |||
1450 | break; | 1461 | break; |
1451 | } | 1462 | } |
1452 | 1463 | ||
1453 | /* Set the role and type to default values. */ | 1464 | /* Set the role to default values. */ |
1454 | if ((tclass == policydb.process_class) || (sock == true)) { | 1465 | if (cladatum && cladatum->default_role == DEFAULT_SOURCE) { |
1455 | /* Use the current role and type of process. */ | ||
1456 | newcontext.role = scontext->role; | 1466 | newcontext.role = scontext->role; |
1457 | newcontext.type = scontext->type; | 1467 | } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { |
1468 | newcontext.role = tcontext->role; | ||
1458 | } else { | 1469 | } else { |
1459 | /* Use the well-defined object role. */ | 1470 | if ((tclass == policydb.process_class) || (sock == true)) |
1460 | newcontext.role = OBJECT_R_VAL; | 1471 | newcontext.role = scontext->role; |
1461 | /* Use the type of the related object. */ | 1472 | else |
1473 | newcontext.role = OBJECT_R_VAL; | ||
1474 | } | ||
1475 | |||
1476 | /* Set the type to default values. */ | ||
1477 | if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { | ||
1478 | newcontext.type = scontext->type; | ||
1479 | } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { | ||
1462 | newcontext.type = tcontext->type; | 1480 | newcontext.type = tcontext->type; |
1481 | } else { | ||
1482 | if ((tclass == policydb.process_class) || (sock == true)) { | ||
1483 | /* Use the type of process. */ | ||
1484 | newcontext.type = scontext->type; | ||
1485 | } else { | ||
1486 | /* Use the type of the related object. */ | ||
1487 | newcontext.type = tcontext->type; | ||
1488 | } | ||
1463 | } | 1489 | } |
1464 | 1490 | ||
1465 | /* Look for a type transition/member/change rule. */ | 1491 | /* Look for a type transition/member/change rule. */ |
@@ -3018,8 +3044,7 @@ out: | |||
3018 | 3044 | ||
3019 | static int (*aurule_callback)(void) = audit_update_lsm_rules; | 3045 | static int (*aurule_callback)(void) = audit_update_lsm_rules; |
3020 | 3046 | ||
3021 | static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, | 3047 | static int aurule_avc_callback(u32 event) |
3022 | u16 class, u32 perms, u32 *retained) | ||
3023 | { | 3048 | { |
3024 | int err = 0; | 3049 | int err = 0; |
3025 | 3050 | ||
@@ -3032,8 +3057,7 @@ static int __init aurule_init(void) | |||
3032 | { | 3057 | { |
3033 | int err; | 3058 | int err; |
3034 | 3059 | ||
3035 | err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET, | 3060 | err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET); |
3036 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | ||
3037 | if (err) | 3061 | if (err) |
3038 | panic("avc_add_callback() failed, error %d\n", err); | 3062 | panic("avc_add_callback() failed, error %d\n", err); |
3039 | 3063 | ||
diff --git a/security/smack/smack.h b/security/smack/smack.h index 4ede719922ed..cc361b8f3d13 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -23,13 +23,19 @@ | |||
23 | #include <linux/lsm_audit.h> | 23 | #include <linux/lsm_audit.h> |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Smack labels were limited to 23 characters for a long time. | ||
27 | */ | ||
28 | #define SMK_LABELLEN 24 | ||
29 | #define SMK_LONGLABEL 256 | ||
30 | |||
31 | /* | ||
32 | * Maximum number of bytes for the levels in a CIPSO IP option. | ||
26 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is | 33 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is |
27 | * bigger than can be used, and 24 is the next lower multiple | 34 | * bigger than can be used, and 24 is the next lower multiple |
28 | * of 8, and there are too many issues if there isn't space set | 35 | * of 8, and there are too many issues if there isn't space set |
29 | * aside for the terminating null byte. | 36 | * aside for the terminating null byte. |
30 | */ | 37 | */ |
31 | #define SMK_MAXLEN 23 | 38 | #define SMK_CIPSOLEN 24 |
32 | #define SMK_LABELLEN (SMK_MAXLEN+1) | ||
33 | 39 | ||
34 | struct superblock_smack { | 40 | struct superblock_smack { |
35 | char *smk_root; | 41 | char *smk_root; |
@@ -66,6 +72,7 @@ struct task_smack { | |||
66 | 72 | ||
67 | #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ | 73 | #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ |
68 | #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ | 74 | #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ |
75 | #define SMK_INODE_CHANGED 0x04 /* smack was transmuted */ | ||
69 | 76 | ||
70 | /* | 77 | /* |
71 | * A label access rule. | 78 | * A label access rule. |
@@ -78,15 +85,6 @@ struct smack_rule { | |||
78 | }; | 85 | }; |
79 | 86 | ||
80 | /* | 87 | /* |
81 | * An entry in the table mapping smack values to | ||
82 | * CIPSO level/category-set values. | ||
83 | */ | ||
84 | struct smack_cipso { | ||
85 | int smk_level; | ||
86 | char smk_catset[SMK_LABELLEN]; | ||
87 | }; | ||
88 | |||
89 | /* | ||
90 | * An entry in the table identifying hosts. | 88 | * An entry in the table identifying hosts. |
91 | */ | 89 | */ |
92 | struct smk_netlbladdr { | 90 | struct smk_netlbladdr { |
@@ -113,22 +111,19 @@ struct smk_netlbladdr { | |||
113 | * interfaces don't. The secid should go away when all of | 111 | * interfaces don't. The secid should go away when all of |
114 | * these components have been repaired. | 112 | * these components have been repaired. |
115 | * | 113 | * |
116 | * If there is a cipso value associated with the label it | 114 | * The cipso value associated with the label gets stored here, too. |
117 | * gets stored here, too. This will most likely be rare as | ||
118 | * the cipso direct mapping in used internally. | ||
119 | * | 115 | * |
120 | * Keep the access rules for this subject label here so that | 116 | * Keep the access rules for this subject label here so that |
121 | * the entire set of rules does not need to be examined every | 117 | * the entire set of rules does not need to be examined every |
122 | * time. | 118 | * time. |
123 | */ | 119 | */ |
124 | struct smack_known { | 120 | struct smack_known { |
125 | struct list_head list; | 121 | struct list_head list; |
126 | char smk_known[SMK_LABELLEN]; | 122 | char *smk_known; |
127 | u32 smk_secid; | 123 | u32 smk_secid; |
128 | struct smack_cipso *smk_cipso; | 124 | struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ |
129 | spinlock_t smk_cipsolock; /* for changing cipso map */ | 125 | struct list_head smk_rules; /* access rules */ |
130 | struct list_head smk_rules; /* access rules */ | 126 | struct mutex smk_rules_lock; /* lock for rules */ |
131 | struct mutex smk_rules_lock; /* lock for the rules */ | ||
132 | }; | 127 | }; |
133 | 128 | ||
134 | /* | 129 | /* |
@@ -165,6 +160,7 @@ struct smack_known { | |||
165 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ | 160 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ |
166 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ | 161 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ |
167 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ | 162 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ |
163 | #define SMACK_CIPSO_MAPPED_DEFAULT 251 /* Also arbitrary */ | ||
168 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ | 164 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ |
169 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ | 165 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ |
170 | #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ | 166 | #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ |
@@ -215,10 +211,9 @@ struct inode_smack *new_inode_smack(char *); | |||
215 | int smk_access_entry(char *, char *, struct list_head *); | 211 | int smk_access_entry(char *, char *, struct list_head *); |
216 | int smk_access(char *, char *, int, struct smk_audit_info *); | 212 | int smk_access(char *, char *, int, struct smk_audit_info *); |
217 | int smk_curacc(char *, u32, struct smk_audit_info *); | 213 | int smk_curacc(char *, u32, struct smk_audit_info *); |
218 | int smack_to_cipso(const char *, struct smack_cipso *); | ||
219 | char *smack_from_cipso(u32, char *); | ||
220 | char *smack_from_secid(const u32); | 214 | char *smack_from_secid(const u32); |
221 | void smk_parse_smack(const char *string, int len, char *smack); | 215 | char *smk_parse_smack(const char *string, int len); |
216 | int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); | ||
222 | char *smk_import(const char *, int); | 217 | char *smk_import(const char *, int); |
223 | struct smack_known *smk_import_entry(const char *, int); | 218 | struct smack_known *smk_import_entry(const char *, int); |
224 | struct smack_known *smk_find_entry(const char *); | 219 | struct smack_known *smk_find_entry(const char *); |
@@ -228,6 +223,7 @@ u32 smack_to_secid(const char *); | |||
228 | * Shared data. | 223 | * Shared data. |
229 | */ | 224 | */ |
230 | extern int smack_cipso_direct; | 225 | extern int smack_cipso_direct; |
226 | extern int smack_cipso_mapped; | ||
231 | extern char *smack_net_ambient; | 227 | extern char *smack_net_ambient; |
232 | extern char *smack_onlycap; | 228 | extern char *smack_onlycap; |
233 | extern const char *smack_cipso_option; | 229 | extern const char *smack_cipso_option; |
@@ -239,24 +235,13 @@ extern struct smack_known smack_known_invalid; | |||
239 | extern struct smack_known smack_known_star; | 235 | extern struct smack_known smack_known_star; |
240 | extern struct smack_known smack_known_web; | 236 | extern struct smack_known smack_known_web; |
241 | 237 | ||
238 | extern struct mutex smack_known_lock; | ||
242 | extern struct list_head smack_known_list; | 239 | extern struct list_head smack_known_list; |
243 | extern struct list_head smk_netlbladdr_list; | 240 | extern struct list_head smk_netlbladdr_list; |
244 | 241 | ||
245 | extern struct security_operations smack_ops; | 242 | extern struct security_operations smack_ops; |
246 | 243 | ||
247 | /* | 244 | /* |
248 | * Stricly for CIPSO level manipulation. | ||
249 | * Set the category bit number in a smack label sized buffer. | ||
250 | */ | ||
251 | static inline void smack_catset_bit(int cat, char *catsetp) | ||
252 | { | ||
253 | if (cat > SMK_LABELLEN * 8) | ||
254 | return; | ||
255 | |||
256 | catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8); | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Is the directory transmuting? | 245 | * Is the directory transmuting? |
261 | */ | 246 | */ |
262 | static inline int smk_inode_transmutable(const struct inode *isp) | 247 | static inline int smk_inode_transmutable(const struct inode *isp) |
@@ -319,7 +304,7 @@ void smack_log(char *subject_label, char *object_label, | |||
319 | static inline void smk_ad_init(struct smk_audit_info *a, const char *func, | 304 | static inline void smk_ad_init(struct smk_audit_info *a, const char *func, |
320 | char type) | 305 | char type) |
321 | { | 306 | { |
322 | memset(a, 0, sizeof(*a)); | 307 | memset(&a->sad, 0, sizeof(a->sad)); |
323 | a->a.type = type; | 308 | a->a.type = type; |
324 | a->a.smack_audit_data = &a->sad; | 309 | a->a.smack_audit_data = &a->sad; |
325 | a->a.smack_audit_data->function = func; | 310 | a->a.smack_audit_data->function = func; |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index c8115f7308f8..9f3705e92712 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -19,37 +19,31 @@ | |||
19 | struct smack_known smack_known_huh = { | 19 | struct smack_known smack_known_huh = { |
20 | .smk_known = "?", | 20 | .smk_known = "?", |
21 | .smk_secid = 2, | 21 | .smk_secid = 2, |
22 | .smk_cipso = NULL, | ||
23 | }; | 22 | }; |
24 | 23 | ||
25 | struct smack_known smack_known_hat = { | 24 | struct smack_known smack_known_hat = { |
26 | .smk_known = "^", | 25 | .smk_known = "^", |
27 | .smk_secid = 3, | 26 | .smk_secid = 3, |
28 | .smk_cipso = NULL, | ||
29 | }; | 27 | }; |
30 | 28 | ||
31 | struct smack_known smack_known_star = { | 29 | struct smack_known smack_known_star = { |
32 | .smk_known = "*", | 30 | .smk_known = "*", |
33 | .smk_secid = 4, | 31 | .smk_secid = 4, |
34 | .smk_cipso = NULL, | ||
35 | }; | 32 | }; |
36 | 33 | ||
37 | struct smack_known smack_known_floor = { | 34 | struct smack_known smack_known_floor = { |
38 | .smk_known = "_", | 35 | .smk_known = "_", |
39 | .smk_secid = 5, | 36 | .smk_secid = 5, |
40 | .smk_cipso = NULL, | ||
41 | }; | 37 | }; |
42 | 38 | ||
43 | struct smack_known smack_known_invalid = { | 39 | struct smack_known smack_known_invalid = { |
44 | .smk_known = "", | 40 | .smk_known = "", |
45 | .smk_secid = 6, | 41 | .smk_secid = 6, |
46 | .smk_cipso = NULL, | ||
47 | }; | 42 | }; |
48 | 43 | ||
49 | struct smack_known smack_known_web = { | 44 | struct smack_known smack_known_web = { |
50 | .smk_known = "@", | 45 | .smk_known = "@", |
51 | .smk_secid = 7, | 46 | .smk_secid = 7, |
52 | .smk_cipso = NULL, | ||
53 | }; | 47 | }; |
54 | 48 | ||
55 | LIST_HEAD(smack_known_list); | 49 | LIST_HEAD(smack_known_list); |
@@ -331,7 +325,7 @@ void smack_log(char *subject_label, char *object_label, int request, | |||
331 | } | 325 | } |
332 | #endif | 326 | #endif |
333 | 327 | ||
334 | static DEFINE_MUTEX(smack_known_lock); | 328 | DEFINE_MUTEX(smack_known_lock); |
335 | 329 | ||
336 | /** | 330 | /** |
337 | * smk_find_entry - find a label on the list, return the list entry | 331 | * smk_find_entry - find a label on the list, return the list entry |
@@ -345,7 +339,7 @@ struct smack_known *smk_find_entry(const char *string) | |||
345 | struct smack_known *skp; | 339 | struct smack_known *skp; |
346 | 340 | ||
347 | list_for_each_entry_rcu(skp, &smack_known_list, list) { | 341 | list_for_each_entry_rcu(skp, &smack_known_list, list) { |
348 | if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0) | 342 | if (strcmp(skp->smk_known, string) == 0) |
349 | return skp; | 343 | return skp; |
350 | } | 344 | } |
351 | 345 | ||
@@ -356,27 +350,76 @@ struct smack_known *smk_find_entry(const char *string) | |||
356 | * smk_parse_smack - parse smack label from a text string | 350 | * smk_parse_smack - parse smack label from a text string |
357 | * @string: a text string that might contain a Smack label | 351 | * @string: a text string that might contain a Smack label |
358 | * @len: the maximum size, or zero if it is NULL terminated. | 352 | * @len: the maximum size, or zero if it is NULL terminated. |
359 | * @smack: parsed smack label, or NULL if parse error | 353 | * |
354 | * Returns a pointer to the clean label, or NULL | ||
360 | */ | 355 | */ |
361 | void smk_parse_smack(const char *string, int len, char *smack) | 356 | char *smk_parse_smack(const char *string, int len) |
362 | { | 357 | { |
363 | int found; | 358 | char *smack; |
364 | int i; | 359 | int i; |
365 | 360 | ||
366 | if (len <= 0 || len > SMK_MAXLEN) | 361 | if (len <= 0) |
367 | len = SMK_MAXLEN; | 362 | len = strlen(string) + 1; |
368 | 363 | ||
369 | for (i = 0, found = 0; i < SMK_LABELLEN; i++) { | 364 | /* |
370 | if (found) | 365 | * Reserve a leading '-' as an indicator that |
371 | smack[i] = '\0'; | 366 | * this isn't a label, but an option to interfaces |
372 | else if (i >= len || string[i] > '~' || string[i] <= ' ' || | 367 | * including /smack/cipso and /smack/cipso2 |
373 | string[i] == '/' || string[i] == '"' || | 368 | */ |
374 | string[i] == '\\' || string[i] == '\'') { | 369 | if (string[0] == '-') |
375 | smack[i] = '\0'; | 370 | return NULL; |
376 | found = 1; | 371 | |
377 | } else | 372 | for (i = 0; i < len; i++) |
378 | smack[i] = string[i]; | 373 | if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' || |
374 | string[i] == '"' || string[i] == '\\' || string[i] == '\'') | ||
375 | break; | ||
376 | |||
377 | if (i == 0 || i >= SMK_LONGLABEL) | ||
378 | return NULL; | ||
379 | |||
380 | smack = kzalloc(i + 1, GFP_KERNEL); | ||
381 | if (smack != NULL) { | ||
382 | strncpy(smack, string, i + 1); | ||
383 | smack[i] = '\0'; | ||
379 | } | 384 | } |
385 | return smack; | ||
386 | } | ||
387 | |||
388 | /** | ||
389 | * smk_netlbl_mls - convert a catset to netlabel mls categories | ||
390 | * @catset: the Smack categories | ||
391 | * @sap: where to put the netlabel categories | ||
392 | * | ||
393 | * Allocates and fills attr.mls | ||
394 | * Returns 0 on success, error code on failure. | ||
395 | */ | ||
396 | int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, | ||
397 | int len) | ||
398 | { | ||
399 | unsigned char *cp; | ||
400 | unsigned char m; | ||
401 | int cat; | ||
402 | int rc; | ||
403 | int byte; | ||
404 | |||
405 | sap->flags |= NETLBL_SECATTR_MLS_CAT; | ||
406 | sap->attr.mls.lvl = level; | ||
407 | sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
408 | sap->attr.mls.cat->startbit = 0; | ||
409 | |||
410 | for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) | ||
411 | for (m = 0x80; m != 0; m >>= 1, cat++) { | ||
412 | if ((m & *cp) == 0) | ||
413 | continue; | ||
414 | rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, | ||
415 | cat, GFP_ATOMIC); | ||
416 | if (rc < 0) { | ||
417 | netlbl_secattr_catmap_free(sap->attr.mls.cat); | ||
418 | return rc; | ||
419 | } | ||
420 | } | ||
421 | |||
422 | return 0; | ||
380 | } | 423 | } |
381 | 424 | ||
382 | /** | 425 | /** |
@@ -390,33 +433,59 @@ void smk_parse_smack(const char *string, int len, char *smack) | |||
390 | struct smack_known *smk_import_entry(const char *string, int len) | 433 | struct smack_known *smk_import_entry(const char *string, int len) |
391 | { | 434 | { |
392 | struct smack_known *skp; | 435 | struct smack_known *skp; |
393 | char smack[SMK_LABELLEN]; | 436 | char *smack; |
437 | int slen; | ||
438 | int rc; | ||
394 | 439 | ||
395 | smk_parse_smack(string, len, smack); | 440 | smack = smk_parse_smack(string, len); |
396 | if (smack[0] == '\0') | 441 | if (smack == NULL) |
397 | return NULL; | 442 | return NULL; |
398 | 443 | ||
399 | mutex_lock(&smack_known_lock); | 444 | mutex_lock(&smack_known_lock); |
400 | 445 | ||
401 | skp = smk_find_entry(smack); | 446 | skp = smk_find_entry(smack); |
447 | if (skp != NULL) | ||
448 | goto freeout; | ||
402 | 449 | ||
403 | if (skp == NULL) { | 450 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); |
404 | skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); | 451 | if (skp == NULL) |
405 | if (skp != NULL) { | 452 | goto freeout; |
406 | strncpy(skp->smk_known, smack, SMK_MAXLEN); | ||
407 | skp->smk_secid = smack_next_secid++; | ||
408 | skp->smk_cipso = NULL; | ||
409 | INIT_LIST_HEAD(&skp->smk_rules); | ||
410 | spin_lock_init(&skp->smk_cipsolock); | ||
411 | mutex_init(&skp->smk_rules_lock); | ||
412 | /* | ||
413 | * Make sure that the entry is actually | ||
414 | * filled before putting it on the list. | ||
415 | */ | ||
416 | list_add_rcu(&skp->list, &smack_known_list); | ||
417 | } | ||
418 | } | ||
419 | 453 | ||
454 | skp->smk_known = smack; | ||
455 | skp->smk_secid = smack_next_secid++; | ||
456 | skp->smk_netlabel.domain = skp->smk_known; | ||
457 | skp->smk_netlabel.flags = | ||
458 | NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
459 | /* | ||
460 | * If direct labeling works use it. | ||
461 | * Otherwise use mapped labeling. | ||
462 | */ | ||
463 | slen = strlen(smack); | ||
464 | if (slen < SMK_CIPSOLEN) | ||
465 | rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known, | ||
466 | &skp->smk_netlabel, slen); | ||
467 | else | ||
468 | rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid, | ||
469 | &skp->smk_netlabel, sizeof(skp->smk_secid)); | ||
470 | |||
471 | if (rc >= 0) { | ||
472 | INIT_LIST_HEAD(&skp->smk_rules); | ||
473 | mutex_init(&skp->smk_rules_lock); | ||
474 | /* | ||
475 | * Make sure that the entry is actually | ||
476 | * filled before putting it on the list. | ||
477 | */ | ||
478 | list_add_rcu(&skp->list, &smack_known_list); | ||
479 | goto unlockout; | ||
480 | } | ||
481 | /* | ||
482 | * smk_netlbl_mls failed. | ||
483 | */ | ||
484 | kfree(skp); | ||
485 | skp = NULL; | ||
486 | freeout: | ||
487 | kfree(smack); | ||
488 | unlockout: | ||
420 | mutex_unlock(&smack_known_lock); | 489 | mutex_unlock(&smack_known_lock); |
421 | 490 | ||
422 | return skp; | 491 | return skp; |
@@ -479,79 +548,9 @@ char *smack_from_secid(const u32 secid) | |||
479 | */ | 548 | */ |
480 | u32 smack_to_secid(const char *smack) | 549 | u32 smack_to_secid(const char *smack) |
481 | { | 550 | { |
482 | struct smack_known *skp; | 551 | struct smack_known *skp = smk_find_entry(smack); |
483 | 552 | ||
484 | rcu_read_lock(); | 553 | if (skp == NULL) |
485 | list_for_each_entry_rcu(skp, &smack_known_list, list) { | 554 | return 0; |
486 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { | 555 | return skp->smk_secid; |
487 | rcu_read_unlock(); | ||
488 | return skp->smk_secid; | ||
489 | } | ||
490 | } | ||
491 | rcu_read_unlock(); | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * smack_from_cipso - find the Smack label associated with a CIPSO option | ||
497 | * @level: Bell & LaPadula level from the network | ||
498 | * @cp: Bell & LaPadula categories from the network | ||
499 | * | ||
500 | * This is a simple lookup in the label table. | ||
501 | * | ||
502 | * Return the matching label from the label list or NULL. | ||
503 | */ | ||
504 | char *smack_from_cipso(u32 level, char *cp) | ||
505 | { | ||
506 | struct smack_known *kp; | ||
507 | char *final = NULL; | ||
508 | |||
509 | rcu_read_lock(); | ||
510 | list_for_each_entry(kp, &smack_known_list, list) { | ||
511 | if (kp->smk_cipso == NULL) | ||
512 | continue; | ||
513 | |||
514 | spin_lock_bh(&kp->smk_cipsolock); | ||
515 | |||
516 | if (kp->smk_cipso->smk_level == level && | ||
517 | memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0) | ||
518 | final = kp->smk_known; | ||
519 | |||
520 | spin_unlock_bh(&kp->smk_cipsolock); | ||
521 | |||
522 | if (final != NULL) | ||
523 | break; | ||
524 | } | ||
525 | rcu_read_unlock(); | ||
526 | |||
527 | return final; | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * smack_to_cipso - find the CIPSO option to go with a Smack label | ||
532 | * @smack: a pointer to the smack label in question | ||
533 | * @cp: where to put the result | ||
534 | * | ||
535 | * Returns zero if a value is available, non-zero otherwise. | ||
536 | */ | ||
537 | int smack_to_cipso(const char *smack, struct smack_cipso *cp) | ||
538 | { | ||
539 | struct smack_known *kp; | ||
540 | int found = 0; | ||
541 | |||
542 | rcu_read_lock(); | ||
543 | list_for_each_entry_rcu(kp, &smack_known_list, list) { | ||
544 | if (kp->smk_known == smack || | ||
545 | strcmp(kp->smk_known, smack) == 0) { | ||
546 | found = 1; | ||
547 | break; | ||
548 | } | ||
549 | } | ||
550 | rcu_read_unlock(); | ||
551 | |||
552 | if (found == 0 || kp->smk_cipso == NULL) | ||
553 | return -ENOENT; | ||
554 | |||
555 | memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); | ||
556 | return 0; | ||
557 | } | 556 | } |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 45c32f074166..d583c0545808 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <linux/pipe_fs_i.h> | 32 | #include <linux/pipe_fs_i.h> |
33 | #include <net/netlabel.h> | ||
34 | #include <net/cipso_ipv4.h> | 33 | #include <net/cipso_ipv4.h> |
35 | #include <linux/audit.h> | 34 | #include <linux/audit.h> |
36 | #include <linux/magic.h> | 35 | #include <linux/magic.h> |
@@ -57,16 +56,23 @@ | |||
57 | static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) | 56 | static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) |
58 | { | 57 | { |
59 | int rc; | 58 | int rc; |
60 | char in[SMK_LABELLEN]; | 59 | char *buffer; |
60 | char *result = NULL; | ||
61 | 61 | ||
62 | if (ip->i_op->getxattr == NULL) | 62 | if (ip->i_op->getxattr == NULL) |
63 | return NULL; | 63 | return NULL; |
64 | 64 | ||
65 | rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN); | 65 | buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); |
66 | if (rc < 0) | 66 | if (buffer == NULL) |
67 | return NULL; | 67 | return NULL; |
68 | 68 | ||
69 | return smk_import(in, rc); | 69 | rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); |
70 | if (rc > 0) | ||
71 | result = smk_import(buffer, rc); | ||
72 | |||
73 | kfree(buffer); | ||
74 | |||
75 | return result; | ||
70 | } | 76 | } |
71 | 77 | ||
72 | /** | 78 | /** |
@@ -79,7 +85,7 @@ struct inode_smack *new_inode_smack(char *smack) | |||
79 | { | 85 | { |
80 | struct inode_smack *isp; | 86 | struct inode_smack *isp; |
81 | 87 | ||
82 | isp = kzalloc(sizeof(struct inode_smack), GFP_KERNEL); | 88 | isp = kzalloc(sizeof(struct inode_smack), GFP_NOFS); |
83 | if (isp == NULL) | 89 | if (isp == NULL) |
84 | return NULL; | 90 | return NULL; |
85 | 91 | ||
@@ -556,13 +562,14 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
556 | void **value, size_t *len) | 562 | void **value, size_t *len) |
557 | { | 563 | { |
558 | struct smack_known *skp; | 564 | struct smack_known *skp; |
565 | struct inode_smack *issp = inode->i_security; | ||
559 | char *csp = smk_of_current(); | 566 | char *csp = smk_of_current(); |
560 | char *isp = smk_of_inode(inode); | 567 | char *isp = smk_of_inode(inode); |
561 | char *dsp = smk_of_inode(dir); | 568 | char *dsp = smk_of_inode(dir); |
562 | int may; | 569 | int may; |
563 | 570 | ||
564 | if (name) { | 571 | if (name) { |
565 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL); | 572 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_NOFS); |
566 | if (*name == NULL) | 573 | if (*name == NULL) |
567 | return -ENOMEM; | 574 | return -ENOMEM; |
568 | } | 575 | } |
@@ -577,12 +584,15 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
577 | * If the access rule allows transmutation and | 584 | * If the access rule allows transmutation and |
578 | * the directory requests transmutation then | 585 | * the directory requests transmutation then |
579 | * by all means transmute. | 586 | * by all means transmute. |
587 | * Mark the inode as changed. | ||
580 | */ | 588 | */ |
581 | if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && | 589 | if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && |
582 | smk_inode_transmutable(dir)) | 590 | smk_inode_transmutable(dir)) { |
583 | isp = dsp; | 591 | isp = dsp; |
592 | issp->smk_flags |= SMK_INODE_CHANGED; | ||
593 | } | ||
584 | 594 | ||
585 | *value = kstrdup(isp, GFP_KERNEL); | 595 | *value = kstrdup(isp, GFP_NOFS); |
586 | if (*value == NULL) | 596 | if (*value == NULL) |
587 | return -ENOMEM; | 597 | return -ENOMEM; |
588 | } | 598 | } |
@@ -821,7 +831,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
821 | * check label validity here so import wont fail on | 831 | * check label validity here so import wont fail on |
822 | * post_setxattr | 832 | * post_setxattr |
823 | */ | 833 | */ |
824 | if (size == 0 || size >= SMK_LABELLEN || | 834 | if (size == 0 || size >= SMK_LONGLABEL || |
825 | smk_import(value, size) == NULL) | 835 | smk_import(value, size) == NULL) |
826 | rc = -EINVAL; | 836 | rc = -EINVAL; |
827 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { | 837 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { |
@@ -1349,7 +1359,7 @@ static int smack_file_receive(struct file *file) | |||
1349 | } | 1359 | } |
1350 | 1360 | ||
1351 | /** | 1361 | /** |
1352 | * smack_dentry_open - Smack dentry open processing | 1362 | * smack_file_open - Smack dentry open processing |
1353 | * @file: the object | 1363 | * @file: the object |
1354 | * @cred: unused | 1364 | * @cred: unused |
1355 | * | 1365 | * |
@@ -1357,7 +1367,7 @@ static int smack_file_receive(struct file *file) | |||
1357 | * | 1367 | * |
1358 | * Returns 0 | 1368 | * Returns 0 |
1359 | */ | 1369 | */ |
1360 | static int smack_dentry_open(struct file *file, const struct cred *cred) | 1370 | static int smack_file_open(struct file *file, const struct cred *cred) |
1361 | { | 1371 | { |
1362 | struct inode_smack *isp = file->f_path.dentry->d_inode->i_security; | 1372 | struct inode_smack *isp = file->f_path.dentry->d_inode->i_security; |
1363 | 1373 | ||
@@ -1820,65 +1830,6 @@ static char *smack_host_label(struct sockaddr_in *sip) | |||
1820 | } | 1830 | } |
1821 | 1831 | ||
1822 | /** | 1832 | /** |
1823 | * smack_set_catset - convert a capset to netlabel mls categories | ||
1824 | * @catset: the Smack categories | ||
1825 | * @sap: where to put the netlabel categories | ||
1826 | * | ||
1827 | * Allocates and fills attr.mls.cat | ||
1828 | */ | ||
1829 | static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap) | ||
1830 | { | ||
1831 | unsigned char *cp; | ||
1832 | unsigned char m; | ||
1833 | int cat; | ||
1834 | int rc; | ||
1835 | int byte; | ||
1836 | |||
1837 | if (!catset) | ||
1838 | return; | ||
1839 | |||
1840 | sap->flags |= NETLBL_SECATTR_MLS_CAT; | ||
1841 | sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
1842 | sap->attr.mls.cat->startbit = 0; | ||
1843 | |||
1844 | for (cat = 1, cp = catset, byte = 0; byte < SMK_LABELLEN; cp++, byte++) | ||
1845 | for (m = 0x80; m != 0; m >>= 1, cat++) { | ||
1846 | if ((m & *cp) == 0) | ||
1847 | continue; | ||
1848 | rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, | ||
1849 | cat, GFP_ATOMIC); | ||
1850 | } | ||
1851 | } | ||
1852 | |||
1853 | /** | ||
1854 | * smack_to_secattr - fill a secattr from a smack value | ||
1855 | * @smack: the smack value | ||
1856 | * @nlsp: where the result goes | ||
1857 | * | ||
1858 | * Casey says that CIPSO is good enough for now. | ||
1859 | * It can be used to effect. | ||
1860 | * It can also be abused to effect when necessary. | ||
1861 | * Apologies to the TSIG group in general and GW in particular. | ||
1862 | */ | ||
1863 | static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) | ||
1864 | { | ||
1865 | struct smack_cipso cipso; | ||
1866 | int rc; | ||
1867 | |||
1868 | nlsp->domain = smack; | ||
1869 | nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
1870 | |||
1871 | rc = smack_to_cipso(smack, &cipso); | ||
1872 | if (rc == 0) { | ||
1873 | nlsp->attr.mls.lvl = cipso.smk_level; | ||
1874 | smack_set_catset(cipso.smk_catset, nlsp); | ||
1875 | } else { | ||
1876 | nlsp->attr.mls.lvl = smack_cipso_direct; | ||
1877 | smack_set_catset(smack, nlsp); | ||
1878 | } | ||
1879 | } | ||
1880 | |||
1881 | /** | ||
1882 | * smack_netlabel - Set the secattr on a socket | 1833 | * smack_netlabel - Set the secattr on a socket |
1883 | * @sk: the socket | 1834 | * @sk: the socket |
1884 | * @labeled: socket label scheme | 1835 | * @labeled: socket label scheme |
@@ -1890,8 +1841,8 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) | |||
1890 | */ | 1841 | */ |
1891 | static int smack_netlabel(struct sock *sk, int labeled) | 1842 | static int smack_netlabel(struct sock *sk, int labeled) |
1892 | { | 1843 | { |
1844 | struct smack_known *skp; | ||
1893 | struct socket_smack *ssp = sk->sk_security; | 1845 | struct socket_smack *ssp = sk->sk_security; |
1894 | struct netlbl_lsm_secattr secattr; | ||
1895 | int rc = 0; | 1846 | int rc = 0; |
1896 | 1847 | ||
1897 | /* | 1848 | /* |
@@ -1909,10 +1860,8 @@ static int smack_netlabel(struct sock *sk, int labeled) | |||
1909 | labeled == SMACK_UNLABELED_SOCKET) | 1860 | labeled == SMACK_UNLABELED_SOCKET) |
1910 | netlbl_sock_delattr(sk); | 1861 | netlbl_sock_delattr(sk); |
1911 | else { | 1862 | else { |
1912 | netlbl_secattr_init(&secattr); | 1863 | skp = smk_find_entry(ssp->smk_out); |
1913 | smack_to_secattr(ssp->smk_out, &secattr); | 1864 | rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); |
1914 | rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr); | ||
1915 | netlbl_secattr_destroy(&secattr); | ||
1916 | } | 1865 | } |
1917 | 1866 | ||
1918 | bh_unlock_sock(sk); | 1867 | bh_unlock_sock(sk); |
@@ -1985,7 +1934,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
1985 | struct socket *sock; | 1934 | struct socket *sock; |
1986 | int rc = 0; | 1935 | int rc = 0; |
1987 | 1936 | ||
1988 | if (value == NULL || size > SMK_LABELLEN || size == 0) | 1937 | if (value == NULL || size > SMK_LONGLABEL || size == 0) |
1989 | return -EACCES; | 1938 | return -EACCES; |
1990 | 1939 | ||
1991 | sp = smk_import(value, size); | 1940 | sp = smk_import(value, size); |
@@ -2552,6 +2501,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2552 | char *final; | 2501 | char *final; |
2553 | char trattr[TRANS_TRUE_SIZE]; | 2502 | char trattr[TRANS_TRUE_SIZE]; |
2554 | int transflag = 0; | 2503 | int transflag = 0; |
2504 | int rc; | ||
2555 | struct dentry *dp; | 2505 | struct dentry *dp; |
2556 | 2506 | ||
2557 | if (inode == NULL) | 2507 | if (inode == NULL) |
@@ -2670,17 +2620,38 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2670 | */ | 2620 | */ |
2671 | dp = dget(opt_dentry); | 2621 | dp = dget(opt_dentry); |
2672 | fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); | 2622 | fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); |
2673 | if (fetched != NULL) { | 2623 | if (fetched != NULL) |
2674 | final = fetched; | 2624 | final = fetched; |
2675 | if (S_ISDIR(inode->i_mode)) { | 2625 | |
2676 | trattr[0] = '\0'; | 2626 | /* |
2677 | inode->i_op->getxattr(dp, | 2627 | * Transmuting directory |
2628 | */ | ||
2629 | if (S_ISDIR(inode->i_mode)) { | ||
2630 | /* | ||
2631 | * If this is a new directory and the label was | ||
2632 | * transmuted when the inode was initialized | ||
2633 | * set the transmute attribute on the directory | ||
2634 | * and mark the inode. | ||
2635 | * | ||
2636 | * If there is a transmute attribute on the | ||
2637 | * directory mark the inode. | ||
2638 | */ | ||
2639 | if (isp->smk_flags & SMK_INODE_CHANGED) { | ||
2640 | isp->smk_flags &= ~SMK_INODE_CHANGED; | ||
2641 | rc = inode->i_op->setxattr(dp, | ||
2678 | XATTR_NAME_SMACKTRANSMUTE, | 2642 | XATTR_NAME_SMACKTRANSMUTE, |
2679 | trattr, TRANS_TRUE_SIZE); | 2643 | TRANS_TRUE, TRANS_TRUE_SIZE, |
2680 | if (strncmp(trattr, TRANS_TRUE, | 2644 | 0); |
2681 | TRANS_TRUE_SIZE) == 0) | 2645 | } else { |
2682 | transflag = SMK_INODE_TRANSMUTE; | 2646 | rc = inode->i_op->getxattr(dp, |
2647 | XATTR_NAME_SMACKTRANSMUTE, trattr, | ||
2648 | TRANS_TRUE_SIZE); | ||
2649 | if (rc >= 0 && strncmp(trattr, TRANS_TRUE, | ||
2650 | TRANS_TRUE_SIZE) != 0) | ||
2651 | rc = -EINVAL; | ||
2683 | } | 2652 | } |
2653 | if (rc >= 0) | ||
2654 | transflag = SMK_INODE_TRANSMUTE; | ||
2684 | } | 2655 | } |
2685 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | 2656 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); |
2686 | isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); | 2657 | isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); |
@@ -2759,7 +2730,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2759 | if (!capable(CAP_MAC_ADMIN)) | 2730 | if (!capable(CAP_MAC_ADMIN)) |
2760 | return -EPERM; | 2731 | return -EPERM; |
2761 | 2732 | ||
2762 | if (value == NULL || size == 0 || size >= SMK_LABELLEN) | 2733 | if (value == NULL || size == 0 || size >= SMK_LONGLABEL) |
2763 | return -EINVAL; | 2734 | return -EINVAL; |
2764 | 2735 | ||
2765 | if (strcmp(name, "current") != 0) | 2736 | if (strcmp(name, "current") != 0) |
@@ -2895,10 +2866,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
2895 | static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, | 2866 | static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, |
2896 | struct socket_smack *ssp) | 2867 | struct socket_smack *ssp) |
2897 | { | 2868 | { |
2898 | struct smack_known *skp; | 2869 | struct smack_known *kp; |
2899 | char smack[SMK_LABELLEN]; | ||
2900 | char *sp; | 2870 | char *sp; |
2901 | int pcat; | 2871 | int found = 0; |
2902 | 2872 | ||
2903 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { | 2873 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { |
2904 | /* | 2874 | /* |
@@ -2906,59 +2876,27 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, | |||
2906 | * If there are flags but no level netlabel isn't | 2876 | * If there are flags but no level netlabel isn't |
2907 | * behaving the way we expect it to. | 2877 | * behaving the way we expect it to. |
2908 | * | 2878 | * |
2909 | * Get the categories, if any | 2879 | * Look it up in the label table |
2910 | * Without guidance regarding the smack value | 2880 | * Without guidance regarding the smack value |
2911 | * for the packet fall back on the network | 2881 | * for the packet fall back on the network |
2912 | * ambient value. | 2882 | * ambient value. |
2913 | */ | 2883 | */ |
2914 | memset(smack, '\0', SMK_LABELLEN); | 2884 | rcu_read_lock(); |
2915 | if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) | 2885 | list_for_each_entry(kp, &smack_known_list, list) { |
2916 | for (pcat = -1;;) { | 2886 | if (sap->attr.mls.lvl != kp->smk_netlabel.attr.mls.lvl) |
2917 | pcat = netlbl_secattr_catmap_walk( | 2887 | continue; |
2918 | sap->attr.mls.cat, pcat + 1); | 2888 | if (memcmp(sap->attr.mls.cat, |
2919 | if (pcat < 0) | 2889 | kp->smk_netlabel.attr.mls.cat, |
2920 | break; | 2890 | SMK_CIPSOLEN) != 0) |
2921 | smack_catset_bit(pcat, smack); | 2891 | continue; |
2922 | } | 2892 | found = 1; |
2923 | /* | 2893 | break; |
2924 | * If it is CIPSO using smack direct mapping | ||
2925 | * we are already done. WeeHee. | ||
2926 | */ | ||
2927 | if (sap->attr.mls.lvl == smack_cipso_direct) { | ||
2928 | /* | ||
2929 | * The label sent is usually on the label list. | ||
2930 | * | ||
2931 | * If it is not we may still want to allow the | ||
2932 | * delivery. | ||
2933 | * | ||
2934 | * If the recipient is accepting all packets | ||
2935 | * because it is using the star ("*") label | ||
2936 | * for SMACK64IPIN provide the web ("@") label | ||
2937 | * so that a directed response will succeed. | ||
2938 | * This is not very correct from a MAC point | ||
2939 | * of view, but gets around the problem that | ||
2940 | * locking prevents adding the newly discovered | ||
2941 | * label to the list. | ||
2942 | * The case where the recipient is not using | ||
2943 | * the star label should obviously fail. | ||
2944 | * The easy way to do this is to provide the | ||
2945 | * star label as the subject label. | ||
2946 | */ | ||
2947 | skp = smk_find_entry(smack); | ||
2948 | if (skp != NULL) | ||
2949 | return skp->smk_known; | ||
2950 | if (ssp != NULL && | ||
2951 | ssp->smk_in == smack_known_star.smk_known) | ||
2952 | return smack_known_web.smk_known; | ||
2953 | return smack_known_star.smk_known; | ||
2954 | } | 2894 | } |
2955 | /* | 2895 | rcu_read_unlock(); |
2956 | * Look it up in the supplied table if it is not | 2896 | |
2957 | * a direct mapping. | 2897 | if (found) |
2958 | */ | 2898 | return kp->smk_known; |
2959 | sp = smack_from_cipso(sap->attr.mls.lvl, smack); | 2899 | |
2960 | if (sp != NULL) | ||
2961 | return sp; | ||
2962 | if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) | 2900 | if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) |
2963 | return smack_known_web.smk_known; | 2901 | return smack_known_web.smk_known; |
2964 | return smack_known_star.smk_known; | 2902 | return smack_known_star.smk_known; |
@@ -3158,11 +3096,13 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
3158 | struct request_sock *req) | 3096 | struct request_sock *req) |
3159 | { | 3097 | { |
3160 | u16 family = sk->sk_family; | 3098 | u16 family = sk->sk_family; |
3099 | struct smack_known *skp; | ||
3161 | struct socket_smack *ssp = sk->sk_security; | 3100 | struct socket_smack *ssp = sk->sk_security; |
3162 | struct netlbl_lsm_secattr secattr; | 3101 | struct netlbl_lsm_secattr secattr; |
3163 | struct sockaddr_in addr; | 3102 | struct sockaddr_in addr; |
3164 | struct iphdr *hdr; | 3103 | struct iphdr *hdr; |
3165 | char *sp; | 3104 | char *sp; |
3105 | char *hsp; | ||
3166 | int rc; | 3106 | int rc; |
3167 | struct smk_audit_info ad; | 3107 | struct smk_audit_info ad; |
3168 | #ifdef CONFIG_AUDIT | 3108 | #ifdef CONFIG_AUDIT |
@@ -3209,16 +3149,14 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
3209 | hdr = ip_hdr(skb); | 3149 | hdr = ip_hdr(skb); |
3210 | addr.sin_addr.s_addr = hdr->saddr; | 3150 | addr.sin_addr.s_addr = hdr->saddr; |
3211 | rcu_read_lock(); | 3151 | rcu_read_lock(); |
3212 | if (smack_host_label(&addr) == NULL) { | 3152 | hsp = smack_host_label(&addr); |
3213 | rcu_read_unlock(); | 3153 | rcu_read_unlock(); |
3214 | netlbl_secattr_init(&secattr); | 3154 | |
3215 | smack_to_secattr(sp, &secattr); | 3155 | if (hsp == NULL) { |
3216 | rc = netlbl_req_setattr(req, &secattr); | 3156 | skp = smk_find_entry(sp); |
3217 | netlbl_secattr_destroy(&secattr); | 3157 | rc = netlbl_req_setattr(req, &skp->smk_netlabel); |
3218 | } else { | 3158 | } else |
3219 | rcu_read_unlock(); | ||
3220 | netlbl_req_delattr(req); | 3159 | netlbl_req_delattr(req); |
3221 | } | ||
3222 | 3160 | ||
3223 | return rc; | 3161 | return rc; |
3224 | } | 3162 | } |
@@ -3400,7 +3338,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, | |||
3400 | char *rule = vrule; | 3338 | char *rule = vrule; |
3401 | 3339 | ||
3402 | if (!rule) { | 3340 | if (!rule) { |
3403 | audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR, | 3341 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, |
3404 | "Smack: missing rule\n"); | 3342 | "Smack: missing rule\n"); |
3405 | return -ENOENT; | 3343 | return -ENOENT; |
3406 | } | 3344 | } |
@@ -3549,7 +3487,7 @@ struct security_operations smack_ops = { | |||
3549 | .file_send_sigiotask = smack_file_send_sigiotask, | 3487 | .file_send_sigiotask = smack_file_send_sigiotask, |
3550 | .file_receive = smack_file_receive, | 3488 | .file_receive = smack_file_receive, |
3551 | 3489 | ||
3552 | .dentry_open = smack_dentry_open, | 3490 | .file_open = smack_file_open, |
3553 | 3491 | ||
3554 | .cred_alloc_blank = smack_cred_alloc_blank, | 3492 | .cred_alloc_blank = smack_cred_alloc_blank, |
3555 | .cred_free = smack_cred_free, | 3493 | .cred_free = smack_cred_free, |
@@ -3643,15 +3581,6 @@ struct security_operations smack_ops = { | |||
3643 | static __init void init_smack_known_list(void) | 3581 | static __init void init_smack_known_list(void) |
3644 | { | 3582 | { |
3645 | /* | 3583 | /* |
3646 | * Initialize CIPSO locks | ||
3647 | */ | ||
3648 | spin_lock_init(&smack_known_huh.smk_cipsolock); | ||
3649 | spin_lock_init(&smack_known_hat.smk_cipsolock); | ||
3650 | spin_lock_init(&smack_known_star.smk_cipsolock); | ||
3651 | spin_lock_init(&smack_known_floor.smk_cipsolock); | ||
3652 | spin_lock_init(&smack_known_invalid.smk_cipsolock); | ||
3653 | spin_lock_init(&smack_known_web.smk_cipsolock); | ||
3654 | /* | ||
3655 | * Initialize rule list locks | 3584 | * Initialize rule list locks |
3656 | */ | 3585 | */ |
3657 | mutex_init(&smack_known_huh.smk_rules_lock); | 3586 | mutex_init(&smack_known_huh.smk_rules_lock); |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 038811cb7e62..1810c9a4ed48 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
25 | #include <net/netlabel.h> | ||
26 | #include <net/cipso_ipv4.h> | 25 | #include <net/cipso_ipv4.h> |
27 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
28 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
@@ -45,6 +44,11 @@ enum smk_inos { | |||
45 | SMK_LOGGING = 10, /* logging */ | 44 | SMK_LOGGING = 10, /* logging */ |
46 | SMK_LOAD_SELF = 11, /* task specific rules */ | 45 | SMK_LOAD_SELF = 11, /* task specific rules */ |
47 | SMK_ACCESSES = 12, /* access policy */ | 46 | SMK_ACCESSES = 12, /* access policy */ |
47 | SMK_MAPPED = 13, /* CIPSO level indicating mapped label */ | ||
48 | SMK_LOAD2 = 14, /* load policy with long labels */ | ||
49 | SMK_LOAD_SELF2 = 15, /* load task specific rules with long labels */ | ||
50 | SMK_ACCESS2 = 16, /* make an access check with long labels */ | ||
51 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ | ||
48 | }; | 52 | }; |
49 | 53 | ||
50 | /* | 54 | /* |
@@ -60,7 +64,7 @@ static DEFINE_MUTEX(smk_netlbladdr_lock); | |||
60 | * If it isn't somehow marked, use this. | 64 | * If it isn't somehow marked, use this. |
61 | * It can be reset via smackfs/ambient | 65 | * It can be reset via smackfs/ambient |
62 | */ | 66 | */ |
63 | char *smack_net_ambient = smack_known_floor.smk_known; | 67 | char *smack_net_ambient; |
64 | 68 | ||
65 | /* | 69 | /* |
66 | * This is the level in a CIPSO header that indicates a | 70 | * This is the level in a CIPSO header that indicates a |
@@ -70,6 +74,13 @@ char *smack_net_ambient = smack_known_floor.smk_known; | |||
70 | int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; | 74 | int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; |
71 | 75 | ||
72 | /* | 76 | /* |
77 | * This is the level in a CIPSO header that indicates a | ||
78 | * secid is contained directly in the category set. | ||
79 | * It can be reset via smackfs/mapped | ||
80 | */ | ||
81 | int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT; | ||
82 | |||
83 | /* | ||
73 | * Unless a process is running with this label even | 84 | * Unless a process is running with this label even |
74 | * having CAP_MAC_OVERRIDE isn't enough to grant | 85 | * having CAP_MAC_OVERRIDE isn't enough to grant |
75 | * privilege to violate MAC policy. If no label is | 86 | * privilege to violate MAC policy. If no label is |
@@ -89,7 +100,7 @@ LIST_HEAD(smk_netlbladdr_list); | |||
89 | 100 | ||
90 | /* | 101 | /* |
91 | * Rule lists are maintained for each label. | 102 | * Rule lists are maintained for each label. |
92 | * This master list is just for reading /smack/load. | 103 | * This master list is just for reading /smack/load and /smack/load2. |
93 | */ | 104 | */ |
94 | struct smack_master_list { | 105 | struct smack_master_list { |
95 | struct list_head list; | 106 | struct list_head list; |
@@ -125,6 +136,18 @@ const char *smack_cipso_option = SMACK_CIPSO_OPTION; | |||
125 | #define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN) | 136 | #define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN) |
126 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) | 137 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) |
127 | 138 | ||
139 | /* | ||
140 | * Stricly for CIPSO level manipulation. | ||
141 | * Set the category bit number in a smack label sized buffer. | ||
142 | */ | ||
143 | static inline void smack_catset_bit(unsigned int cat, char *catsetp) | ||
144 | { | ||
145 | if (cat == 0 || cat > (SMK_CIPSOLEN * 8)) | ||
146 | return; | ||
147 | |||
148 | catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8); | ||
149 | } | ||
150 | |||
128 | /** | 151 | /** |
129 | * smk_netlabel_audit_set - fill a netlbl_audit struct | 152 | * smk_netlabel_audit_set - fill a netlbl_audit struct |
130 | * @nap: structure to fill | 153 | * @nap: structure to fill |
@@ -137,12 +160,10 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) | |||
137 | } | 160 | } |
138 | 161 | ||
139 | /* | 162 | /* |
140 | * Values for parsing single label host rules | 163 | * Value for parsing single label host rules |
141 | * "1.2.3.4 X" | 164 | * "1.2.3.4 X" |
142 | * "192.168.138.129/32 abcdefghijklmnopqrstuvw" | ||
143 | */ | 165 | */ |
144 | #define SMK_NETLBLADDRMIN 9 | 166 | #define SMK_NETLBLADDRMIN 9 |
145 | #define SMK_NETLBLADDRMAX 42 | ||
146 | 167 | ||
147 | /** | 168 | /** |
148 | * smk_set_access - add a rule to the rule list | 169 | * smk_set_access - add a rule to the rule list |
@@ -188,33 +209,47 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, | |||
188 | } | 209 | } |
189 | 210 | ||
190 | /** | 211 | /** |
191 | * smk_parse_rule - parse Smack rule from load string | 212 | * smk_fill_rule - Fill Smack rule from strings |
192 | * @data: string to be parsed whose size is SMK_LOADLEN | 213 | * @subject: subject label string |
214 | * @object: object label string | ||
215 | * @access: access string | ||
193 | * @rule: Smack rule | 216 | * @rule: Smack rule |
194 | * @import: if non-zero, import labels | 217 | * @import: if non-zero, import labels |
218 | * | ||
219 | * Returns 0 on success, -1 on failure | ||
195 | */ | 220 | */ |
196 | static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) | 221 | static int smk_fill_rule(const char *subject, const char *object, |
222 | const char *access, struct smack_rule *rule, | ||
223 | int import) | ||
197 | { | 224 | { |
198 | char smack[SMK_LABELLEN]; | 225 | int rc = -1; |
226 | int done; | ||
227 | const char *cp; | ||
199 | struct smack_known *skp; | 228 | struct smack_known *skp; |
200 | 229 | ||
201 | if (import) { | 230 | if (import) { |
202 | rule->smk_subject = smk_import(data, 0); | 231 | rule->smk_subject = smk_import(subject, 0); |
203 | if (rule->smk_subject == NULL) | 232 | if (rule->smk_subject == NULL) |
204 | return -1; | 233 | return -1; |
205 | 234 | ||
206 | rule->smk_object = smk_import(data + SMK_LABELLEN, 0); | 235 | rule->smk_object = smk_import(object, 0); |
207 | if (rule->smk_object == NULL) | 236 | if (rule->smk_object == NULL) |
208 | return -1; | 237 | return -1; |
209 | } else { | 238 | } else { |
210 | smk_parse_smack(data, 0, smack); | 239 | cp = smk_parse_smack(subject, 0); |
211 | skp = smk_find_entry(smack); | 240 | if (cp == NULL) |
241 | return -1; | ||
242 | skp = smk_find_entry(cp); | ||
243 | kfree(cp); | ||
212 | if (skp == NULL) | 244 | if (skp == NULL) |
213 | return -1; | 245 | return -1; |
214 | rule->smk_subject = skp->smk_known; | 246 | rule->smk_subject = skp->smk_known; |
215 | 247 | ||
216 | smk_parse_smack(data + SMK_LABELLEN, 0, smack); | 248 | cp = smk_parse_smack(object, 0); |
217 | skp = smk_find_entry(smack); | 249 | if (cp == NULL) |
250 | return -1; | ||
251 | skp = smk_find_entry(cp); | ||
252 | kfree(cp); | ||
218 | if (skp == NULL) | 253 | if (skp == NULL) |
219 | return -1; | 254 | return -1; |
220 | rule->smk_object = skp->smk_known; | 255 | rule->smk_object = skp->smk_known; |
@@ -222,90 +257,127 @@ static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) | |||
222 | 257 | ||
223 | rule->smk_access = 0; | 258 | rule->smk_access = 0; |
224 | 259 | ||
225 | switch (data[SMK_LABELLEN + SMK_LABELLEN]) { | 260 | for (cp = access, done = 0; *cp && !done; cp++) { |
226 | case '-': | 261 | switch (*cp) { |
227 | break; | 262 | case '-': |
228 | case 'r': | 263 | break; |
229 | case 'R': | 264 | case 'r': |
230 | rule->smk_access |= MAY_READ; | 265 | case 'R': |
231 | break; | 266 | rule->smk_access |= MAY_READ; |
232 | default: | 267 | break; |
233 | return -1; | 268 | case 'w': |
269 | case 'W': | ||
270 | rule->smk_access |= MAY_WRITE; | ||
271 | break; | ||
272 | case 'x': | ||
273 | case 'X': | ||
274 | rule->smk_access |= MAY_EXEC; | ||
275 | break; | ||
276 | case 'a': | ||
277 | case 'A': | ||
278 | rule->smk_access |= MAY_APPEND; | ||
279 | break; | ||
280 | case 't': | ||
281 | case 'T': | ||
282 | rule->smk_access |= MAY_TRANSMUTE; | ||
283 | break; | ||
284 | default: | ||
285 | done = 1; | ||
286 | break; | ||
287 | } | ||
234 | } | 288 | } |
289 | rc = 0; | ||
235 | 290 | ||
236 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { | 291 | return rc; |
237 | case '-': | 292 | } |
238 | break; | ||
239 | case 'w': | ||
240 | case 'W': | ||
241 | rule->smk_access |= MAY_WRITE; | ||
242 | break; | ||
243 | default: | ||
244 | return -1; | ||
245 | } | ||
246 | 293 | ||
247 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { | 294 | /** |
248 | case '-': | 295 | * smk_parse_rule - parse Smack rule from load string |
249 | break; | 296 | * @data: string to be parsed whose size is SMK_LOADLEN |
250 | case 'x': | 297 | * @rule: Smack rule |
251 | case 'X': | 298 | * @import: if non-zero, import labels |
252 | rule->smk_access |= MAY_EXEC; | 299 | * |
253 | break; | 300 | * Returns 0 on success, -1 on errors. |
254 | default: | 301 | */ |
255 | return -1; | 302 | static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) |
256 | } | 303 | { |
304 | int rc; | ||
257 | 305 | ||
258 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { | 306 | rc = smk_fill_rule(data, data + SMK_LABELLEN, |
259 | case '-': | 307 | data + SMK_LABELLEN + SMK_LABELLEN, rule, import); |
260 | break; | 308 | return rc; |
261 | case 'a': | 309 | } |
262 | case 'A': | ||
263 | rule->smk_access |= MAY_APPEND; | ||
264 | break; | ||
265 | default: | ||
266 | return -1; | ||
267 | } | ||
268 | 310 | ||
269 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) { | 311 | /** |
270 | case '-': | 312 | * smk_parse_long_rule - parse Smack rule from rule string |
271 | break; | 313 | * @data: string to be parsed, null terminated |
272 | case 't': | 314 | * @rule: Smack rule |
273 | case 'T': | 315 | * @import: if non-zero, import labels |
274 | rule->smk_access |= MAY_TRANSMUTE; | 316 | * |
275 | break; | 317 | * Returns 0 on success, -1 on failure |
276 | default: | 318 | */ |
277 | return -1; | 319 | static int smk_parse_long_rule(const char *data, struct smack_rule *rule, |
278 | } | 320 | int import) |
321 | { | ||
322 | char *subject; | ||
323 | char *object; | ||
324 | char *access; | ||
325 | int datalen; | ||
326 | int rc = -1; | ||
279 | 327 | ||
280 | return 0; | 328 | /* |
329 | * This is probably inefficient, but safe. | ||
330 | */ | ||
331 | datalen = strlen(data); | ||
332 | subject = kzalloc(datalen, GFP_KERNEL); | ||
333 | if (subject == NULL) | ||
334 | return -1; | ||
335 | object = kzalloc(datalen, GFP_KERNEL); | ||
336 | if (object == NULL) | ||
337 | goto free_out_s; | ||
338 | access = kzalloc(datalen, GFP_KERNEL); | ||
339 | if (access == NULL) | ||
340 | goto free_out_o; | ||
341 | |||
342 | if (sscanf(data, "%s %s %s", subject, object, access) == 3) | ||
343 | rc = smk_fill_rule(subject, object, access, rule, import); | ||
344 | |||
345 | kfree(access); | ||
346 | free_out_o: | ||
347 | kfree(object); | ||
348 | free_out_s: | ||
349 | kfree(subject); | ||
350 | return rc; | ||
281 | } | 351 | } |
282 | 352 | ||
353 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ | ||
354 | #define SMK_LONG_FMT 1 /* Variable long label format */ | ||
283 | /** | 355 | /** |
284 | * smk_write_load_list - write() for any /smack/load | 356 | * smk_write_rules_list - write() for any /smack rule file |
285 | * @file: file pointer, not actually used | 357 | * @file: file pointer, not actually used |
286 | * @buf: where to get the data from | 358 | * @buf: where to get the data from |
287 | * @count: bytes sent | 359 | * @count: bytes sent |
288 | * @ppos: where to start - must be 0 | 360 | * @ppos: where to start - must be 0 |
289 | * @rule_list: the list of rules to write to | 361 | * @rule_list: the list of rules to write to |
290 | * @rule_lock: lock for the rule list | 362 | * @rule_lock: lock for the rule list |
363 | * @format: /smack/load or /smack/load2 format. | ||
291 | * | 364 | * |
292 | * Get one smack access rule from above. | 365 | * Get one smack access rule from above. |
293 | * The format is exactly: | 366 | * The format for SMK_LONG_FMT is: |
294 | * char subject[SMK_LABELLEN] | 367 | * "subject<whitespace>object<whitespace>access[<whitespace>...]" |
295 | * char object[SMK_LABELLEN] | 368 | * The format for SMK_FIXED24_FMT is exactly: |
296 | * char access[SMK_ACCESSLEN] | 369 | * "subject object rwxat" |
297 | * | ||
298 | * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. | ||
299 | */ | 370 | */ |
300 | static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | 371 | static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, |
301 | size_t count, loff_t *ppos, | 372 | size_t count, loff_t *ppos, |
302 | struct list_head *rule_list, | 373 | struct list_head *rule_list, |
303 | struct mutex *rule_lock) | 374 | struct mutex *rule_lock, int format) |
304 | { | 375 | { |
305 | struct smack_master_list *smlp; | 376 | struct smack_master_list *smlp; |
306 | struct smack_known *skp; | 377 | struct smack_known *skp; |
307 | struct smack_rule *rule; | 378 | struct smack_rule *rule; |
308 | char *data; | 379 | char *data; |
380 | int datalen; | ||
309 | int rc = -EINVAL; | 381 | int rc = -EINVAL; |
310 | int load = 0; | 382 | int load = 0; |
311 | 383 | ||
@@ -315,13 +387,18 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
315 | */ | 387 | */ |
316 | if (*ppos != 0) | 388 | if (*ppos != 0) |
317 | return -EINVAL; | 389 | return -EINVAL; |
318 | /* | ||
319 | * Minor hack for backward compatibility | ||
320 | */ | ||
321 | if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN) | ||
322 | return -EINVAL; | ||
323 | 390 | ||
324 | data = kzalloc(SMK_LOADLEN, GFP_KERNEL); | 391 | if (format == SMK_FIXED24_FMT) { |
392 | /* | ||
393 | * Minor hack for backward compatibility | ||
394 | */ | ||
395 | if (count != SMK_OLOADLEN && count != SMK_LOADLEN) | ||
396 | return -EINVAL; | ||
397 | datalen = SMK_LOADLEN; | ||
398 | } else | ||
399 | datalen = count + 1; | ||
400 | |||
401 | data = kzalloc(datalen, GFP_KERNEL); | ||
325 | if (data == NULL) | 402 | if (data == NULL) |
326 | return -ENOMEM; | 403 | return -ENOMEM; |
327 | 404 | ||
@@ -330,20 +407,29 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
330 | goto out; | 407 | goto out; |
331 | } | 408 | } |
332 | 409 | ||
333 | /* | ||
334 | * More on the minor hack for backward compatibility | ||
335 | */ | ||
336 | if (count == (SMK_OLOADLEN)) | ||
337 | data[SMK_OLOADLEN] = '-'; | ||
338 | |||
339 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); | 410 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); |
340 | if (rule == NULL) { | 411 | if (rule == NULL) { |
341 | rc = -ENOMEM; | 412 | rc = -ENOMEM; |
342 | goto out; | 413 | goto out; |
343 | } | 414 | } |
344 | 415 | ||
345 | if (smk_parse_rule(data, rule, 1)) | 416 | if (format == SMK_LONG_FMT) { |
346 | goto out_free_rule; | 417 | /* |
418 | * Be sure the data string is terminated. | ||
419 | */ | ||
420 | data[count] = '\0'; | ||
421 | if (smk_parse_long_rule(data, rule, 1)) | ||
422 | goto out_free_rule; | ||
423 | } else { | ||
424 | /* | ||
425 | * More on the minor hack for backward compatibility | ||
426 | */ | ||
427 | if (count == (SMK_OLOADLEN)) | ||
428 | data[SMK_OLOADLEN] = '-'; | ||
429 | if (smk_parse_rule(data, rule, 1)) | ||
430 | goto out_free_rule; | ||
431 | } | ||
432 | |||
347 | 433 | ||
348 | if (rule_list == NULL) { | 434 | if (rule_list == NULL) { |
349 | load = 1; | 435 | load = 1; |
@@ -354,18 +440,20 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
354 | 440 | ||
355 | rc = count; | 441 | rc = count; |
356 | /* | 442 | /* |
357 | * If this is "load" as opposed to "load-self" and a new rule | 443 | * If this is a global as opposed to self and a new rule |
358 | * it needs to get added for reporting. | 444 | * it needs to get added for reporting. |
359 | * smk_set_access returns true if there was already a rule | 445 | * smk_set_access returns true if there was already a rule |
360 | * for the subject/object pair, and false if it was new. | 446 | * for the subject/object pair, and false if it was new. |
361 | */ | 447 | */ |
362 | if (load && !smk_set_access(rule, rule_list, rule_lock)) { | 448 | if (!smk_set_access(rule, rule_list, rule_lock)) { |
363 | smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); | 449 | if (load) { |
364 | if (smlp != NULL) { | 450 | smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); |
365 | smlp->smk_rule = rule; | 451 | if (smlp != NULL) { |
366 | list_add_rcu(&smlp->list, &smack_rule_list); | 452 | smlp->smk_rule = rule; |
367 | } else | 453 | list_add_rcu(&smlp->list, &smack_rule_list); |
368 | rc = -ENOMEM; | 454 | } else |
455 | rc = -ENOMEM; | ||
456 | } | ||
369 | goto out; | 457 | goto out; |
370 | } | 458 | } |
371 | 459 | ||
@@ -421,29 +509,18 @@ static void smk_seq_stop(struct seq_file *s, void *v) | |||
421 | /* No-op */ | 509 | /* No-op */ |
422 | } | 510 | } |
423 | 511 | ||
424 | /* | 512 | static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) |
425 | * Seq_file read operations for /smack/load | ||
426 | */ | ||
427 | |||
428 | static void *load_seq_start(struct seq_file *s, loff_t *pos) | ||
429 | { | ||
430 | return smk_seq_start(s, pos, &smack_rule_list); | ||
431 | } | ||
432 | |||
433 | static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
434 | { | 513 | { |
435 | return smk_seq_next(s, v, pos, &smack_rule_list); | 514 | /* |
436 | } | 515 | * Don't show any rules with label names too long for |
437 | 516 | * interface file (/smack/load or /smack/load2) | |
438 | static int load_seq_show(struct seq_file *s, void *v) | 517 | * because you should expect to be able to write |
439 | { | 518 | * anything you read back. |
440 | struct list_head *list = v; | 519 | */ |
441 | struct smack_master_list *smlp = | 520 | if (strlen(srp->smk_subject) >= max || strlen(srp->smk_object) >= max) |
442 | list_entry(list, struct smack_master_list, list); | 521 | return; |
443 | struct smack_rule *srp = smlp->smk_rule; | ||
444 | 522 | ||
445 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | 523 | seq_printf(s, "%s %s", srp->smk_subject, srp->smk_object); |
446 | (char *)srp->smk_object); | ||
447 | 524 | ||
448 | seq_putc(s, ' '); | 525 | seq_putc(s, ' '); |
449 | 526 | ||
@@ -461,13 +538,36 @@ static int load_seq_show(struct seq_file *s, void *v) | |||
461 | seq_putc(s, '-'); | 538 | seq_putc(s, '-'); |
462 | 539 | ||
463 | seq_putc(s, '\n'); | 540 | seq_putc(s, '\n'); |
541 | } | ||
542 | |||
543 | /* | ||
544 | * Seq_file read operations for /smack/load | ||
545 | */ | ||
546 | |||
547 | static void *load2_seq_start(struct seq_file *s, loff_t *pos) | ||
548 | { | ||
549 | return smk_seq_start(s, pos, &smack_rule_list); | ||
550 | } | ||
551 | |||
552 | static void *load2_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
553 | { | ||
554 | return smk_seq_next(s, v, pos, &smack_rule_list); | ||
555 | } | ||
556 | |||
557 | static int load_seq_show(struct seq_file *s, void *v) | ||
558 | { | ||
559 | struct list_head *list = v; | ||
560 | struct smack_master_list *smlp = | ||
561 | list_entry(list, struct smack_master_list, list); | ||
562 | |||
563 | smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN); | ||
464 | 564 | ||
465 | return 0; | 565 | return 0; |
466 | } | 566 | } |
467 | 567 | ||
468 | static const struct seq_operations load_seq_ops = { | 568 | static const struct seq_operations load_seq_ops = { |
469 | .start = load_seq_start, | 569 | .start = load2_seq_start, |
470 | .next = load_seq_next, | 570 | .next = load2_seq_next, |
471 | .show = load_seq_show, | 571 | .show = load_seq_show, |
472 | .stop = smk_seq_stop, | 572 | .stop = smk_seq_stop, |
473 | }; | 573 | }; |
@@ -504,7 +604,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
504 | if (!capable(CAP_MAC_ADMIN)) | 604 | if (!capable(CAP_MAC_ADMIN)) |
505 | return -EPERM; | 605 | return -EPERM; |
506 | 606 | ||
507 | return smk_write_load_list(file, buf, count, ppos, NULL, NULL); | 607 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, |
608 | SMK_FIXED24_FMT); | ||
508 | } | 609 | } |
509 | 610 | ||
510 | static const struct file_operations smk_load_ops = { | 611 | static const struct file_operations smk_load_ops = { |
@@ -574,6 +675,8 @@ static void smk_unlbl_ambient(char *oldambient) | |||
574 | printk(KERN_WARNING "%s:%d remove rc = %d\n", | 675 | printk(KERN_WARNING "%s:%d remove rc = %d\n", |
575 | __func__, __LINE__, rc); | 676 | __func__, __LINE__, rc); |
576 | } | 677 | } |
678 | if (smack_net_ambient == NULL) | ||
679 | smack_net_ambient = smack_known_floor.smk_known; | ||
577 | 680 | ||
578 | rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, | 681 | rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, |
579 | NULL, NULL, &nai); | 682 | NULL, NULL, &nai); |
@@ -605,27 +708,28 @@ static int cipso_seq_show(struct seq_file *s, void *v) | |||
605 | struct list_head *list = v; | 708 | struct list_head *list = v; |
606 | struct smack_known *skp = | 709 | struct smack_known *skp = |
607 | list_entry(list, struct smack_known, list); | 710 | list_entry(list, struct smack_known, list); |
608 | struct smack_cipso *scp = skp->smk_cipso; | 711 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; |
609 | char *cbp; | ||
610 | char sep = '/'; | 712 | char sep = '/'; |
611 | int cat = 1; | ||
612 | int i; | 713 | int i; |
613 | unsigned char m; | ||
614 | 714 | ||
615 | if (scp == NULL) | 715 | /* |
716 | * Don't show a label that could not have been set using | ||
717 | * /smack/cipso. This is in support of the notion that | ||
718 | * anything read from /smack/cipso ought to be writeable | ||
719 | * to /smack/cipso. | ||
720 | * | ||
721 | * /smack/cipso2 should be used instead. | ||
722 | */ | ||
723 | if (strlen(skp->smk_known) >= SMK_LABELLEN) | ||
616 | return 0; | 724 | return 0; |
617 | 725 | ||
618 | seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level); | 726 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); |
619 | 727 | ||
620 | cbp = scp->smk_catset; | 728 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; |
621 | for (i = 0; i < SMK_LABELLEN; i++) | 729 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { |
622 | for (m = 0x80; m != 0; m >>= 1) { | 730 | seq_printf(s, "%c%d", sep, i); |
623 | if (m & cbp[i]) { | 731 | sep = ','; |
624 | seq_printf(s, "%c%d", sep, cat); | 732 | } |
625 | sep = ','; | ||
626 | } | ||
627 | cat++; | ||
628 | } | ||
629 | 733 | ||
630 | seq_putc(s, '\n'); | 734 | seq_putc(s, '\n'); |
631 | 735 | ||
@@ -653,23 +757,24 @@ static int smk_open_cipso(struct inode *inode, struct file *file) | |||
653 | } | 757 | } |
654 | 758 | ||
655 | /** | 759 | /** |
656 | * smk_write_cipso - write() for /smack/cipso | 760 | * smk_set_cipso - do the work for write() for cipso and cipso2 |
657 | * @file: file pointer, not actually used | 761 | * @file: file pointer, not actually used |
658 | * @buf: where to get the data from | 762 | * @buf: where to get the data from |
659 | * @count: bytes sent | 763 | * @count: bytes sent |
660 | * @ppos: where to start | 764 | * @ppos: where to start |
765 | * @format: /smack/cipso or /smack/cipso2 | ||
661 | * | 766 | * |
662 | * Accepts only one cipso rule per write call. | 767 | * Accepts only one cipso rule per write call. |
663 | * Returns number of bytes written or error code, as appropriate | 768 | * Returns number of bytes written or error code, as appropriate |
664 | */ | 769 | */ |
665 | static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | 770 | static ssize_t smk_set_cipso(struct file *file, const char __user *buf, |
666 | size_t count, loff_t *ppos) | 771 | size_t count, loff_t *ppos, int format) |
667 | { | 772 | { |
668 | struct smack_known *skp; | 773 | struct smack_known *skp; |
669 | struct smack_cipso *scp = NULL; | 774 | struct netlbl_lsm_secattr ncats; |
670 | char mapcatset[SMK_LABELLEN]; | 775 | char mapcatset[SMK_CIPSOLEN]; |
671 | int maplevel; | 776 | int maplevel; |
672 | int cat; | 777 | unsigned int cat; |
673 | int catlen; | 778 | int catlen; |
674 | ssize_t rc = -EINVAL; | 779 | ssize_t rc = -EINVAL; |
675 | char *data = NULL; | 780 | char *data = NULL; |
@@ -686,7 +791,8 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
686 | return -EPERM; | 791 | return -EPERM; |
687 | if (*ppos != 0) | 792 | if (*ppos != 0) |
688 | return -EINVAL; | 793 | return -EINVAL; |
689 | if (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX) | 794 | if (format == SMK_FIXED24_FMT && |
795 | (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX)) | ||
690 | return -EINVAL; | 796 | return -EINVAL; |
691 | 797 | ||
692 | data = kzalloc(count + 1, GFP_KERNEL); | 798 | data = kzalloc(count + 1, GFP_KERNEL); |
@@ -698,11 +804,6 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
698 | goto unlockedout; | 804 | goto unlockedout; |
699 | } | 805 | } |
700 | 806 | ||
701 | /* labels cannot begin with a '-' */ | ||
702 | if (data[0] == '-') { | ||
703 | rc = -EINVAL; | ||
704 | goto unlockedout; | ||
705 | } | ||
706 | data[count] = '\0'; | 807 | data[count] = '\0'; |
707 | rule = data; | 808 | rule = data; |
708 | /* | 809 | /* |
@@ -715,7 +816,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
715 | if (skp == NULL) | 816 | if (skp == NULL) |
716 | goto out; | 817 | goto out; |
717 | 818 | ||
718 | rule += SMK_LABELLEN; | 819 | if (format == SMK_FIXED24_FMT) |
820 | rule += SMK_LABELLEN; | ||
821 | else | ||
822 | rule += strlen(skp->smk_known); | ||
823 | |||
719 | ret = sscanf(rule, "%d", &maplevel); | 824 | ret = sscanf(rule, "%d", &maplevel); |
720 | if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL) | 825 | if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL) |
721 | goto out; | 826 | goto out; |
@@ -725,41 +830,29 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
725 | if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM) | 830 | if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM) |
726 | goto out; | 831 | goto out; |
727 | 832 | ||
728 | if (count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN)) | 833 | if (format == SMK_FIXED24_FMT && |
834 | count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN)) | ||
729 | goto out; | 835 | goto out; |
730 | 836 | ||
731 | memset(mapcatset, 0, sizeof(mapcatset)); | 837 | memset(mapcatset, 0, sizeof(mapcatset)); |
732 | 838 | ||
733 | for (i = 0; i < catlen; i++) { | 839 | for (i = 0; i < catlen; i++) { |
734 | rule += SMK_DIGITLEN; | 840 | rule += SMK_DIGITLEN; |
735 | ret = sscanf(rule, "%d", &cat); | 841 | ret = sscanf(rule, "%u", &cat); |
736 | if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) | 842 | if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) |
737 | goto out; | 843 | goto out; |
738 | 844 | ||
739 | smack_catset_bit(cat, mapcatset); | 845 | smack_catset_bit(cat, mapcatset); |
740 | } | 846 | } |
741 | 847 | ||
742 | if (skp->smk_cipso == NULL) { | 848 | rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); |
743 | scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL); | 849 | if (rc >= 0) { |
744 | if (scp == NULL) { | 850 | netlbl_secattr_catmap_free(skp->smk_netlabel.attr.mls.cat); |
745 | rc = -ENOMEM; | 851 | skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat; |
746 | goto out; | 852 | skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; |
747 | } | 853 | rc = count; |
748 | } | 854 | } |
749 | 855 | ||
750 | spin_lock_bh(&skp->smk_cipsolock); | ||
751 | |||
752 | if (scp == NULL) | ||
753 | scp = skp->smk_cipso; | ||
754 | else | ||
755 | skp->smk_cipso = scp; | ||
756 | |||
757 | scp->smk_level = maplevel; | ||
758 | memcpy(scp->smk_catset, mapcatset, sizeof(mapcatset)); | ||
759 | |||
760 | spin_unlock_bh(&skp->smk_cipsolock); | ||
761 | |||
762 | rc = count; | ||
763 | out: | 856 | out: |
764 | mutex_unlock(&smack_cipso_lock); | 857 | mutex_unlock(&smack_cipso_lock); |
765 | unlockedout: | 858 | unlockedout: |
@@ -767,6 +860,22 @@ unlockedout: | |||
767 | return rc; | 860 | return rc; |
768 | } | 861 | } |
769 | 862 | ||
863 | /** | ||
864 | * smk_write_cipso - write() for /smack/cipso | ||
865 | * @file: file pointer, not actually used | ||
866 | * @buf: where to get the data from | ||
867 | * @count: bytes sent | ||
868 | * @ppos: where to start | ||
869 | * | ||
870 | * Accepts only one cipso rule per write call. | ||
871 | * Returns number of bytes written or error code, as appropriate | ||
872 | */ | ||
873 | static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | ||
874 | size_t count, loff_t *ppos) | ||
875 | { | ||
876 | return smk_set_cipso(file, buf, count, ppos, SMK_FIXED24_FMT); | ||
877 | } | ||
878 | |||
770 | static const struct file_operations smk_cipso_ops = { | 879 | static const struct file_operations smk_cipso_ops = { |
771 | .open = smk_open_cipso, | 880 | .open = smk_open_cipso, |
772 | .read = seq_read, | 881 | .read = seq_read, |
@@ -776,6 +885,80 @@ static const struct file_operations smk_cipso_ops = { | |||
776 | }; | 885 | }; |
777 | 886 | ||
778 | /* | 887 | /* |
888 | * Seq_file read operations for /smack/cipso2 | ||
889 | */ | ||
890 | |||
891 | /* | ||
892 | * Print cipso labels in format: | ||
893 | * label level[/cat[,cat]] | ||
894 | */ | ||
895 | static int cipso2_seq_show(struct seq_file *s, void *v) | ||
896 | { | ||
897 | struct list_head *list = v; | ||
898 | struct smack_known *skp = | ||
899 | list_entry(list, struct smack_known, list); | ||
900 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; | ||
901 | char sep = '/'; | ||
902 | int i; | ||
903 | |||
904 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); | ||
905 | |||
906 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; | ||
907 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { | ||
908 | seq_printf(s, "%c%d", sep, i); | ||
909 | sep = ','; | ||
910 | } | ||
911 | |||
912 | seq_putc(s, '\n'); | ||
913 | |||
914 | return 0; | ||
915 | } | ||
916 | |||
917 | static const struct seq_operations cipso2_seq_ops = { | ||
918 | .start = cipso_seq_start, | ||
919 | .next = cipso_seq_next, | ||
920 | .show = cipso2_seq_show, | ||
921 | .stop = smk_seq_stop, | ||
922 | }; | ||
923 | |||
924 | /** | ||
925 | * smk_open_cipso2 - open() for /smack/cipso2 | ||
926 | * @inode: inode structure representing file | ||
927 | * @file: "cipso2" file pointer | ||
928 | * | ||
929 | * Connect our cipso_seq_* operations with /smack/cipso2 | ||
930 | * file_operations | ||
931 | */ | ||
932 | static int smk_open_cipso2(struct inode *inode, struct file *file) | ||
933 | { | ||
934 | return seq_open(file, &cipso2_seq_ops); | ||
935 | } | ||
936 | |||
937 | /** | ||
938 | * smk_write_cipso2 - write() for /smack/cipso2 | ||
939 | * @file: file pointer, not actually used | ||
940 | * @buf: where to get the data from | ||
941 | * @count: bytes sent | ||
942 | * @ppos: where to start | ||
943 | * | ||
944 | * Accepts only one cipso rule per write call. | ||
945 | * Returns number of bytes written or error code, as appropriate | ||
946 | */ | ||
947 | static ssize_t smk_write_cipso2(struct file *file, const char __user *buf, | ||
948 | size_t count, loff_t *ppos) | ||
949 | { | ||
950 | return smk_set_cipso(file, buf, count, ppos, SMK_LONG_FMT); | ||
951 | } | ||
952 | |||
953 | static const struct file_operations smk_cipso2_ops = { | ||
954 | .open = smk_open_cipso2, | ||
955 | .read = seq_read, | ||
956 | .llseek = seq_lseek, | ||
957 | .write = smk_write_cipso2, | ||
958 | .release = seq_release, | ||
959 | }; | ||
960 | |||
961 | /* | ||
779 | * Seq_file read operations for /smack/netlabel | 962 | * Seq_file read operations for /smack/netlabel |
780 | */ | 963 | */ |
781 | 964 | ||
@@ -887,9 +1070,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
887 | { | 1070 | { |
888 | struct smk_netlbladdr *skp; | 1071 | struct smk_netlbladdr *skp; |
889 | struct sockaddr_in newname; | 1072 | struct sockaddr_in newname; |
890 | char smack[SMK_LABELLEN]; | 1073 | char *smack; |
891 | char *sp; | 1074 | char *sp; |
892 | char data[SMK_NETLBLADDRMAX + 1]; | 1075 | char *data; |
893 | char *host = (char *)&newname.sin_addr.s_addr; | 1076 | char *host = (char *)&newname.sin_addr.s_addr; |
894 | int rc; | 1077 | int rc; |
895 | struct netlbl_audit audit_info; | 1078 | struct netlbl_audit audit_info; |
@@ -911,10 +1094,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
911 | return -EPERM; | 1094 | return -EPERM; |
912 | if (*ppos != 0) | 1095 | if (*ppos != 0) |
913 | return -EINVAL; | 1096 | return -EINVAL; |
914 | if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX) | 1097 | if (count < SMK_NETLBLADDRMIN) |
915 | return -EINVAL; | 1098 | return -EINVAL; |
916 | if (copy_from_user(data, buf, count) != 0) | 1099 | |
917 | return -EFAULT; | 1100 | data = kzalloc(count + 1, GFP_KERNEL); |
1101 | if (data == NULL) | ||
1102 | return -ENOMEM; | ||
1103 | |||
1104 | if (copy_from_user(data, buf, count) != 0) { | ||
1105 | rc = -EFAULT; | ||
1106 | goto free_data_out; | ||
1107 | } | ||
1108 | |||
1109 | smack = kzalloc(count + 1, GFP_KERNEL); | ||
1110 | if (smack == NULL) { | ||
1111 | rc = -ENOMEM; | ||
1112 | goto free_data_out; | ||
1113 | } | ||
918 | 1114 | ||
919 | data[count] = '\0'; | 1115 | data[count] = '\0'; |
920 | 1116 | ||
@@ -923,24 +1119,34 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
923 | if (rc != 6) { | 1119 | if (rc != 6) { |
924 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", | 1120 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", |
925 | &host[0], &host[1], &host[2], &host[3], smack); | 1121 | &host[0], &host[1], &host[2], &host[3], smack); |
926 | if (rc != 5) | 1122 | if (rc != 5) { |
927 | return -EINVAL; | 1123 | rc = -EINVAL; |
1124 | goto free_out; | ||
1125 | } | ||
928 | m = BEBITS; | 1126 | m = BEBITS; |
929 | } | 1127 | } |
930 | if (m > BEBITS) | 1128 | if (m > BEBITS) { |
931 | return -EINVAL; | 1129 | rc = -EINVAL; |
1130 | goto free_out; | ||
1131 | } | ||
932 | 1132 | ||
933 | /* if smack begins with '-', its an option, don't import it */ | 1133 | /* |
1134 | * If smack begins with '-', it is an option, don't import it | ||
1135 | */ | ||
934 | if (smack[0] != '-') { | 1136 | if (smack[0] != '-') { |
935 | sp = smk_import(smack, 0); | 1137 | sp = smk_import(smack, 0); |
936 | if (sp == NULL) | 1138 | if (sp == NULL) { |
937 | return -EINVAL; | 1139 | rc = -EINVAL; |
1140 | goto free_out; | ||
1141 | } | ||
938 | } else { | 1142 | } else { |
939 | /* check known options */ | 1143 | /* check known options */ |
940 | if (strcmp(smack, smack_cipso_option) == 0) | 1144 | if (strcmp(smack, smack_cipso_option) == 0) |
941 | sp = (char *)smack_cipso_option; | 1145 | sp = (char *)smack_cipso_option; |
942 | else | 1146 | else { |
943 | return -EINVAL; | 1147 | rc = -EINVAL; |
1148 | goto free_out; | ||
1149 | } | ||
944 | } | 1150 | } |
945 | 1151 | ||
946 | for (temp_mask = 0; m > 0; m--) { | 1152 | for (temp_mask = 0; m > 0; m--) { |
@@ -1006,6 +1212,11 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1006 | 1212 | ||
1007 | mutex_unlock(&smk_netlbladdr_lock); | 1213 | mutex_unlock(&smk_netlbladdr_lock); |
1008 | 1214 | ||
1215 | free_out: | ||
1216 | kfree(smack); | ||
1217 | free_data_out: | ||
1218 | kfree(data); | ||
1219 | |||
1009 | return rc; | 1220 | return rc; |
1010 | } | 1221 | } |
1011 | 1222 | ||
@@ -1119,6 +1330,7 @@ static ssize_t smk_read_direct(struct file *filp, char __user *buf, | |||
1119 | static ssize_t smk_write_direct(struct file *file, const char __user *buf, | 1330 | static ssize_t smk_write_direct(struct file *file, const char __user *buf, |
1120 | size_t count, loff_t *ppos) | 1331 | size_t count, loff_t *ppos) |
1121 | { | 1332 | { |
1333 | struct smack_known *skp; | ||
1122 | char temp[80]; | 1334 | char temp[80]; |
1123 | int i; | 1335 | int i; |
1124 | 1336 | ||
@@ -1136,7 +1348,20 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf, | |||
1136 | if (sscanf(temp, "%d", &i) != 1) | 1348 | if (sscanf(temp, "%d", &i) != 1) |
1137 | return -EINVAL; | 1349 | return -EINVAL; |
1138 | 1350 | ||
1139 | smack_cipso_direct = i; | 1351 | /* |
1352 | * Don't do anything if the value hasn't actually changed. | ||
1353 | * If it is changing reset the level on entries that were | ||
1354 | * set up to be direct when they were created. | ||
1355 | */ | ||
1356 | if (smack_cipso_direct != i) { | ||
1357 | mutex_lock(&smack_known_lock); | ||
1358 | list_for_each_entry_rcu(skp, &smack_known_list, list) | ||
1359 | if (skp->smk_netlabel.attr.mls.lvl == | ||
1360 | smack_cipso_direct) | ||
1361 | skp->smk_netlabel.attr.mls.lvl = i; | ||
1362 | smack_cipso_direct = i; | ||
1363 | mutex_unlock(&smack_known_lock); | ||
1364 | } | ||
1140 | 1365 | ||
1141 | return count; | 1366 | return count; |
1142 | } | 1367 | } |
@@ -1148,6 +1373,84 @@ static const struct file_operations smk_direct_ops = { | |||
1148 | }; | 1373 | }; |
1149 | 1374 | ||
1150 | /** | 1375 | /** |
1376 | * smk_read_mapped - read() for /smack/mapped | ||
1377 | * @filp: file pointer, not actually used | ||
1378 | * @buf: where to put the result | ||
1379 | * @count: maximum to send along | ||
1380 | * @ppos: where to start | ||
1381 | * | ||
1382 | * Returns number of bytes read or error code, as appropriate | ||
1383 | */ | ||
1384 | static ssize_t smk_read_mapped(struct file *filp, char __user *buf, | ||
1385 | size_t count, loff_t *ppos) | ||
1386 | { | ||
1387 | char temp[80]; | ||
1388 | ssize_t rc; | ||
1389 | |||
1390 | if (*ppos != 0) | ||
1391 | return 0; | ||
1392 | |||
1393 | sprintf(temp, "%d", smack_cipso_mapped); | ||
1394 | rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); | ||
1395 | |||
1396 | return rc; | ||
1397 | } | ||
1398 | |||
1399 | /** | ||
1400 | * smk_write_mapped - write() for /smack/mapped | ||
1401 | * @file: file pointer, not actually used | ||
1402 | * @buf: where to get the data from | ||
1403 | * @count: bytes sent | ||
1404 | * @ppos: where to start | ||
1405 | * | ||
1406 | * Returns number of bytes written or error code, as appropriate | ||
1407 | */ | ||
1408 | static ssize_t smk_write_mapped(struct file *file, const char __user *buf, | ||
1409 | size_t count, loff_t *ppos) | ||
1410 | { | ||
1411 | struct smack_known *skp; | ||
1412 | char temp[80]; | ||
1413 | int i; | ||
1414 | |||
1415 | if (!capable(CAP_MAC_ADMIN)) | ||
1416 | return -EPERM; | ||
1417 | |||
1418 | if (count >= sizeof(temp) || count == 0) | ||
1419 | return -EINVAL; | ||
1420 | |||
1421 | if (copy_from_user(temp, buf, count) != 0) | ||
1422 | return -EFAULT; | ||
1423 | |||
1424 | temp[count] = '\0'; | ||
1425 | |||
1426 | if (sscanf(temp, "%d", &i) != 1) | ||
1427 | return -EINVAL; | ||
1428 | |||
1429 | /* | ||
1430 | * Don't do anything if the value hasn't actually changed. | ||
1431 | * If it is changing reset the level on entries that were | ||
1432 | * set up to be mapped when they were created. | ||
1433 | */ | ||
1434 | if (smack_cipso_mapped != i) { | ||
1435 | mutex_lock(&smack_known_lock); | ||
1436 | list_for_each_entry_rcu(skp, &smack_known_list, list) | ||
1437 | if (skp->smk_netlabel.attr.mls.lvl == | ||
1438 | smack_cipso_mapped) | ||
1439 | skp->smk_netlabel.attr.mls.lvl = i; | ||
1440 | smack_cipso_mapped = i; | ||
1441 | mutex_unlock(&smack_known_lock); | ||
1442 | } | ||
1443 | |||
1444 | return count; | ||
1445 | } | ||
1446 | |||
1447 | static const struct file_operations smk_mapped_ops = { | ||
1448 | .read = smk_read_mapped, | ||
1449 | .write = smk_write_mapped, | ||
1450 | .llseek = default_llseek, | ||
1451 | }; | ||
1452 | |||
1453 | /** | ||
1151 | * smk_read_ambient - read() for /smack/ambient | 1454 | * smk_read_ambient - read() for /smack/ambient |
1152 | * @filp: file pointer, not actually used | 1455 | * @filp: file pointer, not actually used |
1153 | * @buf: where to put the result | 1456 | * @buf: where to put the result |
@@ -1195,22 +1498,28 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, | |||
1195 | static ssize_t smk_write_ambient(struct file *file, const char __user *buf, | 1498 | static ssize_t smk_write_ambient(struct file *file, const char __user *buf, |
1196 | size_t count, loff_t *ppos) | 1499 | size_t count, loff_t *ppos) |
1197 | { | 1500 | { |
1198 | char in[SMK_LABELLEN]; | ||
1199 | char *oldambient; | 1501 | char *oldambient; |
1200 | char *smack; | 1502 | char *smack = NULL; |
1503 | char *data; | ||
1504 | int rc = count; | ||
1201 | 1505 | ||
1202 | if (!capable(CAP_MAC_ADMIN)) | 1506 | if (!capable(CAP_MAC_ADMIN)) |
1203 | return -EPERM; | 1507 | return -EPERM; |
1204 | 1508 | ||
1205 | if (count >= SMK_LABELLEN) | 1509 | data = kzalloc(count + 1, GFP_KERNEL); |
1206 | return -EINVAL; | 1510 | if (data == NULL) |
1511 | return -ENOMEM; | ||
1207 | 1512 | ||
1208 | if (copy_from_user(in, buf, count) != 0) | 1513 | if (copy_from_user(data, buf, count) != 0) { |
1209 | return -EFAULT; | 1514 | rc = -EFAULT; |
1515 | goto out; | ||
1516 | } | ||
1210 | 1517 | ||
1211 | smack = smk_import(in, count); | 1518 | smack = smk_import(data, count); |
1212 | if (smack == NULL) | 1519 | if (smack == NULL) { |
1213 | return -EINVAL; | 1520 | rc = -EINVAL; |
1521 | goto out; | ||
1522 | } | ||
1214 | 1523 | ||
1215 | mutex_lock(&smack_ambient_lock); | 1524 | mutex_lock(&smack_ambient_lock); |
1216 | 1525 | ||
@@ -1220,7 +1529,9 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, | |||
1220 | 1529 | ||
1221 | mutex_unlock(&smack_ambient_lock); | 1530 | mutex_unlock(&smack_ambient_lock); |
1222 | 1531 | ||
1223 | return count; | 1532 | out: |
1533 | kfree(data); | ||
1534 | return rc; | ||
1224 | } | 1535 | } |
1225 | 1536 | ||
1226 | static const struct file_operations smk_ambient_ops = { | 1537 | static const struct file_operations smk_ambient_ops = { |
@@ -1271,8 +1582,9 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | |||
1271 | static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | 1582 | static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, |
1272 | size_t count, loff_t *ppos) | 1583 | size_t count, loff_t *ppos) |
1273 | { | 1584 | { |
1274 | char in[SMK_LABELLEN]; | 1585 | char *data; |
1275 | char *sp = smk_of_task(current->cred->security); | 1586 | char *sp = smk_of_task(current->cred->security); |
1587 | int rc = count; | ||
1276 | 1588 | ||
1277 | if (!capable(CAP_MAC_ADMIN)) | 1589 | if (!capable(CAP_MAC_ADMIN)) |
1278 | return -EPERM; | 1590 | return -EPERM; |
@@ -1285,11 +1597,9 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1285 | if (smack_onlycap != NULL && smack_onlycap != sp) | 1597 | if (smack_onlycap != NULL && smack_onlycap != sp) |
1286 | return -EPERM; | 1598 | return -EPERM; |
1287 | 1599 | ||
1288 | if (count >= SMK_LABELLEN) | 1600 | data = kzalloc(count, GFP_KERNEL); |
1289 | return -EINVAL; | 1601 | if (data == NULL) |
1290 | 1602 | return -ENOMEM; | |
1291 | if (copy_from_user(in, buf, count) != 0) | ||
1292 | return -EFAULT; | ||
1293 | 1603 | ||
1294 | /* | 1604 | /* |
1295 | * Should the null string be passed in unset the onlycap value. | 1605 | * Should the null string be passed in unset the onlycap value. |
@@ -1297,10 +1607,17 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1297 | * smk_import only expects to return NULL for errors. It | 1607 | * smk_import only expects to return NULL for errors. It |
1298 | * is usually the case that a nullstring or "\n" would be | 1608 | * is usually the case that a nullstring or "\n" would be |
1299 | * bad to pass to smk_import but in fact this is useful here. | 1609 | * bad to pass to smk_import but in fact this is useful here. |
1610 | * | ||
1611 | * smk_import will also reject a label beginning with '-', | ||
1612 | * so "-usecapabilities" will also work. | ||
1300 | */ | 1613 | */ |
1301 | smack_onlycap = smk_import(in, count); | 1614 | if (copy_from_user(data, buf, count) != 0) |
1615 | rc = -EFAULT; | ||
1616 | else | ||
1617 | smack_onlycap = smk_import(data, count); | ||
1302 | 1618 | ||
1303 | return count; | 1619 | kfree(data); |
1620 | return rc; | ||
1304 | } | 1621 | } |
1305 | 1622 | ||
1306 | static const struct file_operations smk_onlycap_ops = { | 1623 | static const struct file_operations smk_onlycap_ops = { |
@@ -1398,25 +1715,7 @@ static int load_self_seq_show(struct seq_file *s, void *v) | |||
1398 | struct smack_rule *srp = | 1715 | struct smack_rule *srp = |
1399 | list_entry(list, struct smack_rule, list); | 1716 | list_entry(list, struct smack_rule, list); |
1400 | 1717 | ||
1401 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | 1718 | smk_rule_show(s, srp, SMK_LABELLEN); |
1402 | (char *)srp->smk_object); | ||
1403 | |||
1404 | seq_putc(s, ' '); | ||
1405 | |||
1406 | if (srp->smk_access & MAY_READ) | ||
1407 | seq_putc(s, 'r'); | ||
1408 | if (srp->smk_access & MAY_WRITE) | ||
1409 | seq_putc(s, 'w'); | ||
1410 | if (srp->smk_access & MAY_EXEC) | ||
1411 | seq_putc(s, 'x'); | ||
1412 | if (srp->smk_access & MAY_APPEND) | ||
1413 | seq_putc(s, 'a'); | ||
1414 | if (srp->smk_access & MAY_TRANSMUTE) | ||
1415 | seq_putc(s, 't'); | ||
1416 | if (srp->smk_access == 0) | ||
1417 | seq_putc(s, '-'); | ||
1418 | |||
1419 | seq_putc(s, '\n'); | ||
1420 | 1719 | ||
1421 | return 0; | 1720 | return 0; |
1422 | } | 1721 | } |
@@ -1430,7 +1729,7 @@ static const struct seq_operations load_self_seq_ops = { | |||
1430 | 1729 | ||
1431 | 1730 | ||
1432 | /** | 1731 | /** |
1433 | * smk_open_load_self - open() for /smack/load-self | 1732 | * smk_open_load_self - open() for /smack/load-self2 |
1434 | * @inode: inode structure representing file | 1733 | * @inode: inode structure representing file |
1435 | * @file: "load" file pointer | 1734 | * @file: "load" file pointer |
1436 | * | 1735 | * |
@@ -1454,8 +1753,8 @@ static ssize_t smk_write_load_self(struct file *file, const char __user *buf, | |||
1454 | { | 1753 | { |
1455 | struct task_smack *tsp = current_security(); | 1754 | struct task_smack *tsp = current_security(); |
1456 | 1755 | ||
1457 | return smk_write_load_list(file, buf, count, ppos, &tsp->smk_rules, | 1756 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, |
1458 | &tsp->smk_rules_lock); | 1757 | &tsp->smk_rules_lock, SMK_FIXED24_FMT); |
1459 | } | 1758 | } |
1460 | 1759 | ||
1461 | static const struct file_operations smk_load_self_ops = { | 1760 | static const struct file_operations smk_load_self_ops = { |
@@ -1467,24 +1766,42 @@ static const struct file_operations smk_load_self_ops = { | |||
1467 | }; | 1766 | }; |
1468 | 1767 | ||
1469 | /** | 1768 | /** |
1470 | * smk_write_access - handle access check transaction | 1769 | * smk_user_access - handle access check transaction |
1471 | * @file: file pointer | 1770 | * @file: file pointer |
1472 | * @buf: data from user space | 1771 | * @buf: data from user space |
1473 | * @count: bytes sent | 1772 | * @count: bytes sent |
1474 | * @ppos: where to start - must be 0 | 1773 | * @ppos: where to start - must be 0 |
1475 | */ | 1774 | */ |
1476 | static ssize_t smk_write_access(struct file *file, const char __user *buf, | 1775 | static ssize_t smk_user_access(struct file *file, const char __user *buf, |
1477 | size_t count, loff_t *ppos) | 1776 | size_t count, loff_t *ppos, int format) |
1478 | { | 1777 | { |
1479 | struct smack_rule rule; | 1778 | struct smack_rule rule; |
1480 | char *data; | 1779 | char *data; |
1780 | char *cod; | ||
1481 | int res; | 1781 | int res; |
1482 | 1782 | ||
1483 | data = simple_transaction_get(file, buf, count); | 1783 | data = simple_transaction_get(file, buf, count); |
1484 | if (IS_ERR(data)) | 1784 | if (IS_ERR(data)) |
1485 | return PTR_ERR(data); | 1785 | return PTR_ERR(data); |
1486 | 1786 | ||
1487 | if (count < SMK_LOADLEN || smk_parse_rule(data, &rule, 0)) | 1787 | if (format == SMK_FIXED24_FMT) { |
1788 | if (count < SMK_LOADLEN) | ||
1789 | return -EINVAL; | ||
1790 | res = smk_parse_rule(data, &rule, 0); | ||
1791 | } else { | ||
1792 | /* | ||
1793 | * Copy the data to make sure the string is terminated. | ||
1794 | */ | ||
1795 | cod = kzalloc(count + 1, GFP_KERNEL); | ||
1796 | if (cod == NULL) | ||
1797 | return -ENOMEM; | ||
1798 | memcpy(cod, data, count); | ||
1799 | cod[count] = '\0'; | ||
1800 | res = smk_parse_long_rule(cod, &rule, 0); | ||
1801 | kfree(cod); | ||
1802 | } | ||
1803 | |||
1804 | if (res) | ||
1488 | return -EINVAL; | 1805 | return -EINVAL; |
1489 | 1806 | ||
1490 | res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access, | 1807 | res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access, |
@@ -1493,7 +1810,23 @@ static ssize_t smk_write_access(struct file *file, const char __user *buf, | |||
1493 | data[1] = '\0'; | 1810 | data[1] = '\0'; |
1494 | 1811 | ||
1495 | simple_transaction_set(file, 2); | 1812 | simple_transaction_set(file, 2); |
1496 | return SMK_LOADLEN; | 1813 | |
1814 | if (format == SMK_FIXED24_FMT) | ||
1815 | return SMK_LOADLEN; | ||
1816 | return count; | ||
1817 | } | ||
1818 | |||
1819 | /** | ||
1820 | * smk_write_access - handle access check transaction | ||
1821 | * @file: file pointer | ||
1822 | * @buf: data from user space | ||
1823 | * @count: bytes sent | ||
1824 | * @ppos: where to start - must be 0 | ||
1825 | */ | ||
1826 | static ssize_t smk_write_access(struct file *file, const char __user *buf, | ||
1827 | size_t count, loff_t *ppos) | ||
1828 | { | ||
1829 | return smk_user_access(file, buf, count, ppos, SMK_FIXED24_FMT); | ||
1497 | } | 1830 | } |
1498 | 1831 | ||
1499 | static const struct file_operations smk_access_ops = { | 1832 | static const struct file_operations smk_access_ops = { |
@@ -1503,6 +1836,163 @@ static const struct file_operations smk_access_ops = { | |||
1503 | .llseek = generic_file_llseek, | 1836 | .llseek = generic_file_llseek, |
1504 | }; | 1837 | }; |
1505 | 1838 | ||
1839 | |||
1840 | /* | ||
1841 | * Seq_file read operations for /smack/load2 | ||
1842 | */ | ||
1843 | |||
1844 | static int load2_seq_show(struct seq_file *s, void *v) | ||
1845 | { | ||
1846 | struct list_head *list = v; | ||
1847 | struct smack_master_list *smlp = | ||
1848 | list_entry(list, struct smack_master_list, list); | ||
1849 | |||
1850 | smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL); | ||
1851 | |||
1852 | return 0; | ||
1853 | } | ||
1854 | |||
1855 | static const struct seq_operations load2_seq_ops = { | ||
1856 | .start = load2_seq_start, | ||
1857 | .next = load2_seq_next, | ||
1858 | .show = load2_seq_show, | ||
1859 | .stop = smk_seq_stop, | ||
1860 | }; | ||
1861 | |||
1862 | /** | ||
1863 | * smk_open_load2 - open() for /smack/load2 | ||
1864 | * @inode: inode structure representing file | ||
1865 | * @file: "load2" file pointer | ||
1866 | * | ||
1867 | * For reading, use load2_seq_* seq_file reading operations. | ||
1868 | */ | ||
1869 | static int smk_open_load2(struct inode *inode, struct file *file) | ||
1870 | { | ||
1871 | return seq_open(file, &load2_seq_ops); | ||
1872 | } | ||
1873 | |||
1874 | /** | ||
1875 | * smk_write_load2 - write() for /smack/load2 | ||
1876 | * @file: file pointer, not actually used | ||
1877 | * @buf: where to get the data from | ||
1878 | * @count: bytes sent | ||
1879 | * @ppos: where to start - must be 0 | ||
1880 | * | ||
1881 | */ | ||
1882 | static ssize_t smk_write_load2(struct file *file, const char __user *buf, | ||
1883 | size_t count, loff_t *ppos) | ||
1884 | { | ||
1885 | /* | ||
1886 | * Must have privilege. | ||
1887 | */ | ||
1888 | if (!capable(CAP_MAC_ADMIN)) | ||
1889 | return -EPERM; | ||
1890 | |||
1891 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, | ||
1892 | SMK_LONG_FMT); | ||
1893 | } | ||
1894 | |||
1895 | static const struct file_operations smk_load2_ops = { | ||
1896 | .open = smk_open_load2, | ||
1897 | .read = seq_read, | ||
1898 | .llseek = seq_lseek, | ||
1899 | .write = smk_write_load2, | ||
1900 | .release = seq_release, | ||
1901 | }; | ||
1902 | |||
1903 | /* | ||
1904 | * Seq_file read operations for /smack/load-self2 | ||
1905 | */ | ||
1906 | |||
1907 | static void *load_self2_seq_start(struct seq_file *s, loff_t *pos) | ||
1908 | { | ||
1909 | struct task_smack *tsp = current_security(); | ||
1910 | |||
1911 | return smk_seq_start(s, pos, &tsp->smk_rules); | ||
1912 | } | ||
1913 | |||
1914 | static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
1915 | { | ||
1916 | struct task_smack *tsp = current_security(); | ||
1917 | |||
1918 | return smk_seq_next(s, v, pos, &tsp->smk_rules); | ||
1919 | } | ||
1920 | |||
1921 | static int load_self2_seq_show(struct seq_file *s, void *v) | ||
1922 | { | ||
1923 | struct list_head *list = v; | ||
1924 | struct smack_rule *srp = | ||
1925 | list_entry(list, struct smack_rule, list); | ||
1926 | |||
1927 | smk_rule_show(s, srp, SMK_LONGLABEL); | ||
1928 | |||
1929 | return 0; | ||
1930 | } | ||
1931 | |||
1932 | static const struct seq_operations load_self2_seq_ops = { | ||
1933 | .start = load_self2_seq_start, | ||
1934 | .next = load_self2_seq_next, | ||
1935 | .show = load_self2_seq_show, | ||
1936 | .stop = smk_seq_stop, | ||
1937 | }; | ||
1938 | |||
1939 | /** | ||
1940 | * smk_open_load_self2 - open() for /smack/load-self2 | ||
1941 | * @inode: inode structure representing file | ||
1942 | * @file: "load" file pointer | ||
1943 | * | ||
1944 | * For reading, use load_seq_* seq_file reading operations. | ||
1945 | */ | ||
1946 | static int smk_open_load_self2(struct inode *inode, struct file *file) | ||
1947 | { | ||
1948 | return seq_open(file, &load_self2_seq_ops); | ||
1949 | } | ||
1950 | |||
1951 | /** | ||
1952 | * smk_write_load_self2 - write() for /smack/load-self2 | ||
1953 | * @file: file pointer, not actually used | ||
1954 | * @buf: where to get the data from | ||
1955 | * @count: bytes sent | ||
1956 | * @ppos: where to start - must be 0 | ||
1957 | * | ||
1958 | */ | ||
1959 | static ssize_t smk_write_load_self2(struct file *file, const char __user *buf, | ||
1960 | size_t count, loff_t *ppos) | ||
1961 | { | ||
1962 | struct task_smack *tsp = current_security(); | ||
1963 | |||
1964 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, | ||
1965 | &tsp->smk_rules_lock, SMK_LONG_FMT); | ||
1966 | } | ||
1967 | |||
1968 | static const struct file_operations smk_load_self2_ops = { | ||
1969 | .open = smk_open_load_self2, | ||
1970 | .read = seq_read, | ||
1971 | .llseek = seq_lseek, | ||
1972 | .write = smk_write_load_self2, | ||
1973 | .release = seq_release, | ||
1974 | }; | ||
1975 | |||
1976 | /** | ||
1977 | * smk_write_access2 - handle access check transaction | ||
1978 | * @file: file pointer | ||
1979 | * @buf: data from user space | ||
1980 | * @count: bytes sent | ||
1981 | * @ppos: where to start - must be 0 | ||
1982 | */ | ||
1983 | static ssize_t smk_write_access2(struct file *file, const char __user *buf, | ||
1984 | size_t count, loff_t *ppos) | ||
1985 | { | ||
1986 | return smk_user_access(file, buf, count, ppos, SMK_LONG_FMT); | ||
1987 | } | ||
1988 | |||
1989 | static const struct file_operations smk_access2_ops = { | ||
1990 | .write = smk_write_access2, | ||
1991 | .read = simple_transaction_read, | ||
1992 | .release = simple_transaction_release, | ||
1993 | .llseek = generic_file_llseek, | ||
1994 | }; | ||
1995 | |||
1506 | /** | 1996 | /** |
1507 | * smk_fill_super - fill the /smackfs superblock | 1997 | * smk_fill_super - fill the /smackfs superblock |
1508 | * @sb: the empty superblock | 1998 | * @sb: the empty superblock |
@@ -1539,6 +2029,16 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
1539 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, | 2029 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, |
1540 | [SMK_ACCESSES] = { | 2030 | [SMK_ACCESSES] = { |
1541 | "access", &smk_access_ops, S_IRUGO|S_IWUGO}, | 2031 | "access", &smk_access_ops, S_IRUGO|S_IWUGO}, |
2032 | [SMK_MAPPED] = { | ||
2033 | "mapped", &smk_mapped_ops, S_IRUGO|S_IWUSR}, | ||
2034 | [SMK_LOAD2] = { | ||
2035 | "load2", &smk_load2_ops, S_IRUGO|S_IWUSR}, | ||
2036 | [SMK_LOAD_SELF2] = { | ||
2037 | "load-self2", &smk_load_self2_ops, S_IRUGO|S_IWUGO}, | ||
2038 | [SMK_ACCESS2] = { | ||
2039 | "access2", &smk_access2_ops, S_IRUGO|S_IWUGO}, | ||
2040 | [SMK_CIPSO2] = { | ||
2041 | "cipso2", &smk_cipso2_ops, S_IRUGO|S_IWUSR}, | ||
1542 | /* last one */ | 2042 | /* last one */ |
1543 | {""} | 2043 | {""} |
1544 | }; | 2044 | }; |
@@ -1581,6 +2081,15 @@ static struct file_system_type smk_fs_type = { | |||
1581 | 2081 | ||
1582 | static struct vfsmount *smackfs_mount; | 2082 | static struct vfsmount *smackfs_mount; |
1583 | 2083 | ||
2084 | static int __init smk_preset_netlabel(struct smack_known *skp) | ||
2085 | { | ||
2086 | skp->smk_netlabel.domain = skp->smk_known; | ||
2087 | skp->smk_netlabel.flags = | ||
2088 | NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
2089 | return smk_netlbl_mls(smack_cipso_direct, skp->smk_known, | ||
2090 | &skp->smk_netlabel, strlen(skp->smk_known)); | ||
2091 | } | ||
2092 | |||
1584 | /** | 2093 | /** |
1585 | * init_smk_fs - get the smackfs superblock | 2094 | * init_smk_fs - get the smackfs superblock |
1586 | * | 2095 | * |
@@ -1597,6 +2106,7 @@ static struct vfsmount *smackfs_mount; | |||
1597 | static int __init init_smk_fs(void) | 2106 | static int __init init_smk_fs(void) |
1598 | { | 2107 | { |
1599 | int err; | 2108 | int err; |
2109 | int rc; | ||
1600 | 2110 | ||
1601 | if (!security_module_enable(&smack_ops)) | 2111 | if (!security_module_enable(&smack_ops)) |
1602 | return 0; | 2112 | return 0; |
@@ -1614,6 +2124,25 @@ static int __init init_smk_fs(void) | |||
1614 | smk_cipso_doi(); | 2124 | smk_cipso_doi(); |
1615 | smk_unlbl_ambient(NULL); | 2125 | smk_unlbl_ambient(NULL); |
1616 | 2126 | ||
2127 | rc = smk_preset_netlabel(&smack_known_floor); | ||
2128 | if (err == 0 && rc < 0) | ||
2129 | err = rc; | ||
2130 | rc = smk_preset_netlabel(&smack_known_hat); | ||
2131 | if (err == 0 && rc < 0) | ||
2132 | err = rc; | ||
2133 | rc = smk_preset_netlabel(&smack_known_huh); | ||
2134 | if (err == 0 && rc < 0) | ||
2135 | err = rc; | ||
2136 | rc = smk_preset_netlabel(&smack_known_invalid); | ||
2137 | if (err == 0 && rc < 0) | ||
2138 | err = rc; | ||
2139 | rc = smk_preset_netlabel(&smack_known_star); | ||
2140 | if (err == 0 && rc < 0) | ||
2141 | err = rc; | ||
2142 | rc = smk_preset_netlabel(&smack_known_web); | ||
2143 | if (err == 0 && rc < 0) | ||
2144 | err = rc; | ||
2145 | |||
1617 | return err; | 2146 | return err; |
1618 | } | 2147 | } |
1619 | 2148 | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 8656b16eef7b..2e0f12c62938 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -850,14 +850,9 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
850 | policy_list[TOMOYO_ID_MANAGER], | 850 | policy_list[TOMOYO_ID_MANAGER], |
851 | }; | 851 | }; |
852 | int error = is_delete ? -ENOENT : -ENOMEM; | 852 | int error = is_delete ? -ENOENT : -ENOMEM; |
853 | if (tomoyo_domain_def(manager)) { | 853 | if (!tomoyo_correct_domain(manager) && |
854 | if (!tomoyo_correct_domain(manager)) | 854 | !tomoyo_correct_word(manager)) |
855 | return -EINVAL; | 855 | return -EINVAL; |
856 | e.is_domain = true; | ||
857 | } else { | ||
858 | if (!tomoyo_correct_path(manager)) | ||
859 | return -EINVAL; | ||
860 | } | ||
861 | e.manager = tomoyo_get_name(manager); | 856 | e.manager = tomoyo_get_name(manager); |
862 | if (e.manager) { | 857 | if (e.manager) { |
863 | error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, | 858 | error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, |
@@ -932,23 +927,14 @@ static bool tomoyo_manager(void) | |||
932 | return true; | 927 | return true; |
933 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) | 928 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) |
934 | return false; | 929 | return false; |
935 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. | ||
936 | policy_list[TOMOYO_ID_MANAGER], head.list) { | ||
937 | if (!ptr->head.is_deleted && ptr->is_domain | ||
938 | && !tomoyo_pathcmp(domainname, ptr->manager)) { | ||
939 | found = true; | ||
940 | break; | ||
941 | } | ||
942 | } | ||
943 | if (found) | ||
944 | return true; | ||
945 | exe = tomoyo_get_exe(); | 930 | exe = tomoyo_get_exe(); |
946 | if (!exe) | 931 | if (!exe) |
947 | return false; | 932 | return false; |
948 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. | 933 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
949 | policy_list[TOMOYO_ID_MANAGER], head.list) { | 934 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
950 | if (!ptr->head.is_deleted && !ptr->is_domain | 935 | if (!ptr->head.is_deleted && |
951 | && !strcmp(exe, ptr->manager->name)) { | 936 | (!tomoyo_pathcmp(domainname, ptr->manager) || |
937 | !strcmp(exe, ptr->manager->name))) { | ||
952 | found = true; | 938 | found = true; |
953 | break; | 939 | break; |
954 | } | 940 | } |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 30fd98369700..75e4dc1c02a0 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -860,7 +860,6 @@ struct tomoyo_aggregator { | |||
860 | /* Structure for policy manager. */ | 860 | /* Structure for policy manager. */ |
861 | struct tomoyo_manager { | 861 | struct tomoyo_manager { |
862 | struct tomoyo_acl_head head; | 862 | struct tomoyo_acl_head head; |
863 | bool is_domain; /* True if manager is a domainname. */ | ||
864 | /* A path to program or a domainname. */ | 863 | /* A path to program or a domainname. */ |
865 | const struct tomoyo_path_info *manager; | 864 | const struct tomoyo_path_info *manager; |
866 | }; | 865 | }; |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 620d37c159a3..c2d04a50f76a 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -319,14 +319,14 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, | |||
319 | } | 319 | } |
320 | 320 | ||
321 | /** | 321 | /** |
322 | * tomoyo_dentry_open - Target for security_dentry_open(). | 322 | * tomoyo_file_open - Target for security_file_open(). |
323 | * | 323 | * |
324 | * @f: Pointer to "struct file". | 324 | * @f: Pointer to "struct file". |
325 | * @cred: Pointer to "struct cred". | 325 | * @cred: Pointer to "struct cred". |
326 | * | 326 | * |
327 | * Returns 0 on success, negative value otherwise. | 327 | * Returns 0 on success, negative value otherwise. |
328 | */ | 328 | */ |
329 | static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | 329 | static int tomoyo_file_open(struct file *f, const struct cred *cred) |
330 | { | 330 | { |
331 | int flags = f->f_flags; | 331 | int flags = f->f_flags; |
332 | /* Don't check read permission here if called from do_execve(). */ | 332 | /* Don't check read permission here if called from do_execve(). */ |
@@ -510,7 +510,7 @@ static struct security_operations tomoyo_security_ops = { | |||
510 | .bprm_set_creds = tomoyo_bprm_set_creds, | 510 | .bprm_set_creds = tomoyo_bprm_set_creds, |
511 | .bprm_check_security = tomoyo_bprm_check_security, | 511 | .bprm_check_security = tomoyo_bprm_check_security, |
512 | .file_fcntl = tomoyo_file_fcntl, | 512 | .file_fcntl = tomoyo_file_fcntl, |
513 | .dentry_open = tomoyo_dentry_open, | 513 | .file_open = tomoyo_file_open, |
514 | .path_truncate = tomoyo_path_truncate, | 514 | .path_truncate = tomoyo_path_truncate, |
515 | .path_unlink = tomoyo_path_unlink, | 515 | .path_unlink = tomoyo_path_unlink, |
516 | .path_mkdir = tomoyo_path_mkdir, | 516 | .path_mkdir = tomoyo_path_mkdir, |
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 573723843a04..83554ee8a587 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
@@ -18,7 +18,12 @@ | |||
18 | #include <linux/prctl.h> | 18 | #include <linux/prctl.h> |
19 | #include <linux/ratelimit.h> | 19 | #include <linux/ratelimit.h> |
20 | 20 | ||
21 | static int ptrace_scope = 1; | 21 | #define YAMA_SCOPE_DISABLED 0 |
22 | #define YAMA_SCOPE_RELATIONAL 1 | ||
23 | #define YAMA_SCOPE_CAPABILITY 2 | ||
24 | #define YAMA_SCOPE_NO_ATTACH 3 | ||
25 | |||
26 | static int ptrace_scope = YAMA_SCOPE_RELATIONAL; | ||
22 | 27 | ||
23 | /* describe a ptrace relationship for potential exception */ | 28 | /* describe a ptrace relationship for potential exception */ |
24 | struct ptrace_relation { | 29 | struct ptrace_relation { |
@@ -251,17 +256,32 @@ static int yama_ptrace_access_check(struct task_struct *child, | |||
251 | return rc; | 256 | return rc; |
252 | 257 | ||
253 | /* require ptrace target be a child of ptracer on attach */ | 258 | /* require ptrace target be a child of ptracer on attach */ |
254 | if (mode == PTRACE_MODE_ATTACH && | 259 | if (mode == PTRACE_MODE_ATTACH) { |
255 | ptrace_scope && | 260 | switch (ptrace_scope) { |
256 | !task_is_descendant(current, child) && | 261 | case YAMA_SCOPE_DISABLED: |
257 | !ptracer_exception_found(current, child) && | 262 | /* No additional restrictions. */ |
258 | !capable(CAP_SYS_PTRACE)) | 263 | break; |
259 | rc = -EPERM; | 264 | case YAMA_SCOPE_RELATIONAL: |
265 | if (!task_is_descendant(current, child) && | ||
266 | !ptracer_exception_found(current, child) && | ||
267 | !ns_capable(task_user_ns(child), CAP_SYS_PTRACE)) | ||
268 | rc = -EPERM; | ||
269 | break; | ||
270 | case YAMA_SCOPE_CAPABILITY: | ||
271 | if (!ns_capable(task_user_ns(child), CAP_SYS_PTRACE)) | ||
272 | rc = -EPERM; | ||
273 | break; | ||
274 | case YAMA_SCOPE_NO_ATTACH: | ||
275 | default: | ||
276 | rc = -EPERM; | ||
277 | break; | ||
278 | } | ||
279 | } | ||
260 | 280 | ||
261 | if (rc) { | 281 | if (rc) { |
262 | char name[sizeof(current->comm)]; | 282 | char name[sizeof(current->comm)]; |
263 | printk_ratelimited(KERN_NOTICE "ptrace of non-child" | 283 | printk_ratelimited(KERN_NOTICE |
264 | " pid %d was attempted by: %s (pid %d)\n", | 284 | "ptrace of pid %d was attempted by: %s (pid %d)\n", |
265 | child->pid, | 285 | child->pid, |
266 | get_task_comm(name, current), | 286 | get_task_comm(name, current), |
267 | current->pid); | 287 | current->pid); |
@@ -279,8 +299,27 @@ static struct security_operations yama_ops = { | |||
279 | }; | 299 | }; |
280 | 300 | ||
281 | #ifdef CONFIG_SYSCTL | 301 | #ifdef CONFIG_SYSCTL |
302 | static int yama_dointvec_minmax(struct ctl_table *table, int write, | ||
303 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
304 | { | ||
305 | int rc; | ||
306 | |||
307 | if (write && !capable(CAP_SYS_PTRACE)) | ||
308 | return -EPERM; | ||
309 | |||
310 | rc = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | ||
311 | if (rc) | ||
312 | return rc; | ||
313 | |||
314 | /* Lock the max value if it ever gets set. */ | ||
315 | if (write && *(int *)table->data == *(int *)table->extra2) | ||
316 | table->extra1 = table->extra2; | ||
317 | |||
318 | return rc; | ||
319 | } | ||
320 | |||
282 | static int zero; | 321 | static int zero; |
283 | static int one = 1; | 322 | static int max_scope = YAMA_SCOPE_NO_ATTACH; |
284 | 323 | ||
285 | struct ctl_path yama_sysctl_path[] = { | 324 | struct ctl_path yama_sysctl_path[] = { |
286 | { .procname = "kernel", }, | 325 | { .procname = "kernel", }, |
@@ -294,9 +333,9 @@ static struct ctl_table yama_sysctl_table[] = { | |||
294 | .data = &ptrace_scope, | 333 | .data = &ptrace_scope, |
295 | .maxlen = sizeof(int), | 334 | .maxlen = sizeof(int), |
296 | .mode = 0644, | 335 | .mode = 0644, |
297 | .proc_handler = proc_dointvec_minmax, | 336 | .proc_handler = yama_dointvec_minmax, |
298 | .extra1 = &zero, | 337 | .extra1 = &zero, |
299 | .extra2 = &one, | 338 | .extra2 = &max_scope, |
300 | }, | 339 | }, |
301 | { } | 340 | { } |
302 | }; | 341 | }; |