diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-16 18:40:50 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-16 18:40:50 -0500 |
commit | 2a74dbb9a86e8102dcd07d284135b4530a84826e (patch) | |
tree | a54403e312b6062dfb57bd904ba8b8ce3b11e720 | |
parent | 770b6cb4d21fb3e3df2a7a51e186a3c14db1ec30 (diff) | |
parent | e93072374112db9dc86635934ee761249be28370 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"A quiet cycle for the security subsystem with just a few maintenance
updates."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
Smack: create a sysfs mount point for smackfs
Smack: use select not depends in Kconfig
Yama: remove locking from delete path
Yama: add RCU to drop read locking
drivers/char/tpm: remove tasklet and cleanup
KEYS: Use keyring_alloc() to create special keyrings
KEYS: Reduce initial permissions on keys
KEYS: Make the session and process keyrings per-thread
seccomp: Make syscall skipping and nr changes more consistent
key: Fix resource leak
keys: Fix unreachable code
KEYS: Add payload preparsing opportunity prior to key instantiate or update
-rw-r--r-- | Documentation/prctl/seccomp_filter.txt | 74 | ||||
-rw-r--r-- | Documentation/security/keys.txt | 17 | ||||
-rw-r--r-- | arch/x86/kernel/vsyscall_64.c | 110 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ibmvtpm.c | 81 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ibmvtpm.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 12 | ||||
-rw-r--r-- | fs/nfs/idmap.c | 12 | ||||
-rw-r--r-- | include/linux/cred.h | 17 | ||||
-rw-r--r-- | include/linux/key.h | 1 | ||||
-rw-r--r-- | kernel/cred.c | 127 | ||||
-rw-r--r-- | kernel/seccomp.c | 13 | ||||
-rw-r--r-- | net/dns_resolver/dns_key.c | 15 | ||||
-rw-r--r-- | security/keys/key.c | 6 | ||||
-rw-r--r-- | security/keys/keyctl.c | 15 | ||||
-rw-r--r-- | security/keys/keyring.c | 10 | ||||
-rw-r--r-- | security/keys/process_keys.c | 92 | ||||
-rw-r--r-- | security/keys/request_key.c | 21 | ||||
-rw-r--r-- | security/smack/Kconfig | 6 | ||||
-rw-r--r-- | security/smack/smackfs.c | 17 | ||||
-rw-r--r-- | security/yama/yama_lsm.c | 88 |
20 files changed, 369 insertions, 370 deletions
diff --git a/Documentation/prctl/seccomp_filter.txt b/Documentation/prctl/seccomp_filter.txt index 597c3c581375..1e469ef75778 100644 --- a/Documentation/prctl/seccomp_filter.txt +++ b/Documentation/prctl/seccomp_filter.txt | |||
@@ -95,12 +95,15 @@ SECCOMP_RET_KILL: | |||
95 | 95 | ||
96 | SECCOMP_RET_TRAP: | 96 | SECCOMP_RET_TRAP: |
97 | Results in the kernel sending a SIGSYS signal to the triggering | 97 | Results in the kernel sending a SIGSYS signal to the triggering |
98 | task without executing the system call. The kernel will | 98 | task without executing the system call. siginfo->si_call_addr |
99 | rollback the register state to just before the system call | 99 | will show the address of the system call instruction, and |
100 | entry such that a signal handler in the task will be able to | 100 | siginfo->si_syscall and siginfo->si_arch will indicate which |
101 | inspect the ucontext_t->uc_mcontext registers and emulate | 101 | syscall was attempted. The program counter will be as though |
102 | system call success or failure upon return from the signal | 102 | the syscall happened (i.e. it will not point to the syscall |
103 | handler. | 103 | instruction). The return value register will contain an arch- |
104 | dependent value -- if resuming execution, set it to something | ||
105 | sensible. (The architecture dependency is because replacing | ||
106 | it with -ENOSYS could overwrite some useful information.) | ||
104 | 107 | ||
105 | The SECCOMP_RET_DATA portion of the return value will be passed | 108 | The SECCOMP_RET_DATA portion of the return value will be passed |
106 | as si_errno. | 109 | as si_errno. |
@@ -123,6 +126,18 @@ SECCOMP_RET_TRACE: | |||
123 | the BPF program return value will be available to the tracer | 126 | the BPF program return value will be available to the tracer |
124 | via PTRACE_GETEVENTMSG. | 127 | via PTRACE_GETEVENTMSG. |
125 | 128 | ||
129 | The tracer can skip the system call by changing the syscall number | ||
130 | to -1. Alternatively, the tracer can change the system call | ||
131 | requested by changing the system call to a valid syscall number. If | ||
132 | the tracer asks to skip the system call, then the system call will | ||
133 | appear to return the value that the tracer puts in the return value | ||
134 | register. | ||
135 | |||
136 | The seccomp check will not be run again after the tracer is | ||
137 | notified. (This means that seccomp-based sandboxes MUST NOT | ||
138 | allow use of ptrace, even of other sandboxed processes, without | ||
139 | extreme care; ptracers can use this mechanism to escape.) | ||
140 | |||
126 | SECCOMP_RET_ALLOW: | 141 | SECCOMP_RET_ALLOW: |
127 | Results in the system call being executed. | 142 | Results in the system call being executed. |
128 | 143 | ||
@@ -161,3 +176,50 @@ architecture supports both ptrace_event and seccomp, it will be able to | |||
161 | support seccomp filter with minor fixup: SIGSYS support and seccomp return | 176 | support seccomp filter with minor fixup: SIGSYS support and seccomp return |
162 | value checking. Then it must just add CONFIG_HAVE_ARCH_SECCOMP_FILTER | 177 | value checking. Then it must just add CONFIG_HAVE_ARCH_SECCOMP_FILTER |
163 | to its arch-specific Kconfig. | 178 | to its arch-specific Kconfig. |
179 | |||
180 | |||
181 | |||
182 | Caveats | ||
183 | ------- | ||
184 | |||
185 | The vDSO can cause some system calls to run entirely in userspace, | ||
186 | leading to surprises when you run programs on different machines that | ||
187 | fall back to real syscalls. To minimize these surprises on x86, make | ||
188 | sure you test with | ||
189 | /sys/devices/system/clocksource/clocksource0/current_clocksource set to | ||
190 | something like acpi_pm. | ||
191 | |||
192 | On x86-64, vsyscall emulation is enabled by default. (vsyscalls are | ||
193 | legacy variants on vDSO calls.) Currently, emulated vsyscalls will honor seccomp, with a few oddities: | ||
194 | |||
195 | - A return value of SECCOMP_RET_TRAP will set a si_call_addr pointing to | ||
196 | the vsyscall entry for the given call and not the address after the | ||
197 | 'syscall' instruction. Any code which wants to restart the call | ||
198 | should be aware that (a) a ret instruction has been emulated and (b) | ||
199 | trying to resume the syscall will again trigger the standard vsyscall | ||
200 | emulation security checks, making resuming the syscall mostly | ||
201 | pointless. | ||
202 | |||
203 | - A return value of SECCOMP_RET_TRACE will signal the tracer as usual, | ||
204 | but the syscall may not be changed to another system call using the | ||
205 | orig_rax register. It may only be changed to -1 order to skip the | ||
206 | currently emulated call. Any other change MAY terminate the process. | ||
207 | The rip value seen by the tracer will be the syscall entry address; | ||
208 | this is different from normal behavior. The tracer MUST NOT modify | ||
209 | rip or rsp. (Do not rely on other changes terminating the process. | ||
210 | They might work. For example, on some kernels, choosing a syscall | ||
211 | that only exists in future kernels will be correctly emulated (by | ||
212 | returning -ENOSYS). | ||
213 | |||
214 | To detect this quirky behavior, check for addr & ~0x0C00 == | ||
215 | 0xFFFFFFFFFF600000. (For SECCOMP_RET_TRACE, use rip. For | ||
216 | SECCOMP_RET_TRAP, use siginfo->si_call_addr.) Do not check any other | ||
217 | condition: future kernels may improve vsyscall emulation and current | ||
218 | kernels in vsyscall=native mode will behave differently, but the | ||
219 | instructions at 0xF...F600{0,4,8,C}00 will not be system calls in these | ||
220 | cases. | ||
221 | |||
222 | Note that modern systems are unlikely to use vsyscalls at all -- they | ||
223 | are a legacy feature and they are considerably slower than standard | ||
224 | syscalls. New code will use the vDSO, and vDSO-issued system calls | ||
225 | are indistinguishable from normal system calls. | ||
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index 7d9ca92022d8..7b4145d00452 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt | |||
@@ -994,6 +994,23 @@ payload contents" for more information. | |||
994 | reference pointer if successful. | 994 | reference pointer if successful. |
995 | 995 | ||
996 | 996 | ||
997 | (*) A keyring can be created by: | ||
998 | |||
999 | struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, | ||
1000 | const struct cred *cred, | ||
1001 | key_perm_t perm, | ||
1002 | unsigned long flags, | ||
1003 | struct key *dest); | ||
1004 | |||
1005 | This creates a keyring with the given attributes and returns it. If dest | ||
1006 | is not NULL, the new keyring will be linked into the keyring to which it | ||
1007 | points. No permission checks are made upon the destination keyring. | ||
1008 | |||
1009 | Error EDQUOT can be returned if the keyring would overload the quota (pass | ||
1010 | KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted | ||
1011 | towards the user's quota). Error ENOMEM can also be returned. | ||
1012 | |||
1013 | |||
997 | (*) To check the validity of a key, this function can be called: | 1014 | (*) To check the validity of a key, this function can be called: |
998 | 1015 | ||
999 | int validate_key(struct key *key); | 1016 | int validate_key(struct key *key); |
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 3a3e8c9e280d..9a907a67be8f 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c | |||
@@ -145,19 +145,6 @@ static int addr_to_vsyscall_nr(unsigned long addr) | |||
145 | return nr; | 145 | return nr; |
146 | } | 146 | } |
147 | 147 | ||
148 | #ifdef CONFIG_SECCOMP | ||
149 | static int vsyscall_seccomp(struct task_struct *tsk, int syscall_nr) | ||
150 | { | ||
151 | if (!seccomp_mode(&tsk->seccomp)) | ||
152 | return 0; | ||
153 | task_pt_regs(tsk)->orig_ax = syscall_nr; | ||
154 | task_pt_regs(tsk)->ax = syscall_nr; | ||
155 | return __secure_computing(syscall_nr); | ||
156 | } | ||
157 | #else | ||
158 | #define vsyscall_seccomp(_tsk, _nr) 0 | ||
159 | #endif | ||
160 | |||
161 | static bool write_ok_or_segv(unsigned long ptr, size_t size) | 148 | static bool write_ok_or_segv(unsigned long ptr, size_t size) |
162 | { | 149 | { |
163 | /* | 150 | /* |
@@ -190,10 +177,9 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) | |||
190 | { | 177 | { |
191 | struct task_struct *tsk; | 178 | struct task_struct *tsk; |
192 | unsigned long caller; | 179 | unsigned long caller; |
193 | int vsyscall_nr; | 180 | int vsyscall_nr, syscall_nr, tmp; |
194 | int prev_sig_on_uaccess_error; | 181 | int prev_sig_on_uaccess_error; |
195 | long ret; | 182 | long ret; |
196 | int skip; | ||
197 | 183 | ||
198 | /* | 184 | /* |
199 | * No point in checking CS -- the only way to get here is a user mode | 185 | * No point in checking CS -- the only way to get here is a user mode |
@@ -225,56 +211,84 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) | |||
225 | } | 211 | } |
226 | 212 | ||
227 | tsk = current; | 213 | tsk = current; |
228 | /* | ||
229 | * With a real vsyscall, page faults cause SIGSEGV. We want to | ||
230 | * preserve that behavior to make writing exploits harder. | ||
231 | */ | ||
232 | prev_sig_on_uaccess_error = current_thread_info()->sig_on_uaccess_error; | ||
233 | current_thread_info()->sig_on_uaccess_error = 1; | ||
234 | 214 | ||
235 | /* | 215 | /* |
216 | * Check for access_ok violations and find the syscall nr. | ||
217 | * | ||
236 | * NULL is a valid user pointer (in the access_ok sense) on 32-bit and | 218 | * NULL is a valid user pointer (in the access_ok sense) on 32-bit and |
237 | * 64-bit, so we don't need to special-case it here. For all the | 219 | * 64-bit, so we don't need to special-case it here. For all the |
238 | * vsyscalls, NULL means "don't write anything" not "write it at | 220 | * vsyscalls, NULL means "don't write anything" not "write it at |
239 | * address 0". | 221 | * address 0". |
240 | */ | 222 | */ |
241 | ret = -EFAULT; | ||
242 | skip = 0; | ||
243 | switch (vsyscall_nr) { | 223 | switch (vsyscall_nr) { |
244 | case 0: | 224 | case 0: |
245 | skip = vsyscall_seccomp(tsk, __NR_gettimeofday); | ||
246 | if (skip) | ||
247 | break; | ||
248 | |||
249 | if (!write_ok_or_segv(regs->di, sizeof(struct timeval)) || | 225 | if (!write_ok_or_segv(regs->di, sizeof(struct timeval)) || |
250 | !write_ok_or_segv(regs->si, sizeof(struct timezone))) | 226 | !write_ok_or_segv(regs->si, sizeof(struct timezone))) { |
251 | break; | 227 | ret = -EFAULT; |
228 | goto check_fault; | ||
229 | } | ||
230 | |||
231 | syscall_nr = __NR_gettimeofday; | ||
232 | break; | ||
233 | |||
234 | case 1: | ||
235 | if (!write_ok_or_segv(regs->di, sizeof(time_t))) { | ||
236 | ret = -EFAULT; | ||
237 | goto check_fault; | ||
238 | } | ||
239 | |||
240 | syscall_nr = __NR_time; | ||
241 | break; | ||
242 | |||
243 | case 2: | ||
244 | if (!write_ok_or_segv(regs->di, sizeof(unsigned)) || | ||
245 | !write_ok_or_segv(regs->si, sizeof(unsigned))) { | ||
246 | ret = -EFAULT; | ||
247 | goto check_fault; | ||
248 | } | ||
249 | |||
250 | syscall_nr = __NR_getcpu; | ||
251 | break; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Handle seccomp. regs->ip must be the original value. | ||
256 | * See seccomp_send_sigsys and Documentation/prctl/seccomp_filter.txt. | ||
257 | * | ||
258 | * We could optimize the seccomp disabled case, but performance | ||
259 | * here doesn't matter. | ||
260 | */ | ||
261 | regs->orig_ax = syscall_nr; | ||
262 | regs->ax = -ENOSYS; | ||
263 | tmp = secure_computing(syscall_nr); | ||
264 | if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) { | ||
265 | warn_bad_vsyscall(KERN_DEBUG, regs, | ||
266 | "seccomp tried to change syscall nr or ip"); | ||
267 | do_exit(SIGSYS); | ||
268 | } | ||
269 | if (tmp) | ||
270 | goto do_ret; /* skip requested */ | ||
252 | 271 | ||
272 | /* | ||
273 | * With a real vsyscall, page faults cause SIGSEGV. We want to | ||
274 | * preserve that behavior to make writing exploits harder. | ||
275 | */ | ||
276 | prev_sig_on_uaccess_error = current_thread_info()->sig_on_uaccess_error; | ||
277 | current_thread_info()->sig_on_uaccess_error = 1; | ||
278 | |||
279 | ret = -EFAULT; | ||
280 | switch (vsyscall_nr) { | ||
281 | case 0: | ||
253 | ret = sys_gettimeofday( | 282 | ret = sys_gettimeofday( |
254 | (struct timeval __user *)regs->di, | 283 | (struct timeval __user *)regs->di, |
255 | (struct timezone __user *)regs->si); | 284 | (struct timezone __user *)regs->si); |
256 | break; | 285 | break; |
257 | 286 | ||
258 | case 1: | 287 | case 1: |
259 | skip = vsyscall_seccomp(tsk, __NR_time); | ||
260 | if (skip) | ||
261 | break; | ||
262 | |||
263 | if (!write_ok_or_segv(regs->di, sizeof(time_t))) | ||
264 | break; | ||
265 | |||
266 | ret = sys_time((time_t __user *)regs->di); | 288 | ret = sys_time((time_t __user *)regs->di); |
267 | break; | 289 | break; |
268 | 290 | ||
269 | case 2: | 291 | case 2: |
270 | skip = vsyscall_seccomp(tsk, __NR_getcpu); | ||
271 | if (skip) | ||
272 | break; | ||
273 | |||
274 | if (!write_ok_or_segv(regs->di, sizeof(unsigned)) || | ||
275 | !write_ok_or_segv(regs->si, sizeof(unsigned))) | ||
276 | break; | ||
277 | |||
278 | ret = sys_getcpu((unsigned __user *)regs->di, | 292 | ret = sys_getcpu((unsigned __user *)regs->di, |
279 | (unsigned __user *)regs->si, | 293 | (unsigned __user *)regs->si, |
280 | NULL); | 294 | NULL); |
@@ -283,12 +297,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) | |||
283 | 297 | ||
284 | current_thread_info()->sig_on_uaccess_error = prev_sig_on_uaccess_error; | 298 | current_thread_info()->sig_on_uaccess_error = prev_sig_on_uaccess_error; |
285 | 299 | ||
286 | if (skip) { | 300 | check_fault: |
287 | if ((long)regs->ax <= 0L) /* seccomp errno emulation */ | ||
288 | goto do_ret; | ||
289 | goto done; /* seccomp trace/trap */ | ||
290 | } | ||
291 | |||
292 | if (ret == -EFAULT) { | 301 | if (ret == -EFAULT) { |
293 | /* Bad news -- userspace fed a bad pointer to a vsyscall. */ | 302 | /* Bad news -- userspace fed a bad pointer to a vsyscall. */ |
294 | warn_bad_vsyscall(KERN_INFO, regs, | 303 | warn_bad_vsyscall(KERN_INFO, regs, |
@@ -311,7 +320,6 @@ do_ret: | |||
311 | /* Emulate a ret instruction. */ | 320 | /* Emulate a ret instruction. */ |
312 | regs->ip = caller; | 321 | regs->ip = caller; |
313 | regs->sp += 8; | 322 | regs->sp += 8; |
314 | done: | ||
315 | return true; | 323 | return true; |
316 | 324 | ||
317 | sigsegv: | 325 | sigsegv: |
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 7da840d487d2..9978609d93b2 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c | |||
@@ -38,8 +38,6 @@ static struct vio_device_id tpm_ibmvtpm_device_table[] = { | |||
38 | }; | 38 | }; |
39 | MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table); | 39 | MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table); |
40 | 40 | ||
41 | DECLARE_WAIT_QUEUE_HEAD(wq); | ||
42 | |||
43 | /** | 41 | /** |
44 | * ibmvtpm_send_crq - Send a CRQ request | 42 | * ibmvtpm_send_crq - Send a CRQ request |
45 | * @vdev: vio device struct | 43 | * @vdev: vio device struct |
@@ -83,6 +81,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
83 | { | 81 | { |
84 | struct ibmvtpm_dev *ibmvtpm; | 82 | struct ibmvtpm_dev *ibmvtpm; |
85 | u16 len; | 83 | u16 len; |
84 | int sig; | ||
86 | 85 | ||
87 | ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data; | 86 | ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data; |
88 | 87 | ||
@@ -91,22 +90,23 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
91 | return 0; | 90 | return 0; |
92 | } | 91 | } |
93 | 92 | ||
94 | wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0); | 93 | sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0); |
94 | if (sig) | ||
95 | return -EINTR; | ||
96 | |||
97 | len = ibmvtpm->res_len; | ||
95 | 98 | ||
96 | if (count < ibmvtpm->crq_res.len) { | 99 | if (count < len) { |
97 | dev_err(ibmvtpm->dev, | 100 | dev_err(ibmvtpm->dev, |
98 | "Invalid size in recv: count=%ld, crq_size=%d\n", | 101 | "Invalid size in recv: count=%ld, crq_size=%d\n", |
99 | count, ibmvtpm->crq_res.len); | 102 | count, len); |
100 | return -EIO; | 103 | return -EIO; |
101 | } | 104 | } |
102 | 105 | ||
103 | spin_lock(&ibmvtpm->rtce_lock); | 106 | spin_lock(&ibmvtpm->rtce_lock); |
104 | memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, ibmvtpm->crq_res.len); | 107 | memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, len); |
105 | memset(ibmvtpm->rtce_buf, 0, ibmvtpm->crq_res.len); | 108 | memset(ibmvtpm->rtce_buf, 0, len); |
106 | ibmvtpm->crq_res.valid = 0; | 109 | ibmvtpm->res_len = 0; |
107 | ibmvtpm->crq_res.msg = 0; | ||
108 | len = ibmvtpm->crq_res.len; | ||
109 | ibmvtpm->crq_res.len = 0; | ||
110 | spin_unlock(&ibmvtpm->rtce_lock); | 110 | spin_unlock(&ibmvtpm->rtce_lock); |
111 | return len; | 111 | return len; |
112 | } | 112 | } |
@@ -273,7 +273,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) | |||
273 | int rc = 0; | 273 | int rc = 0; |
274 | 274 | ||
275 | free_irq(vdev->irq, ibmvtpm); | 275 | free_irq(vdev->irq, ibmvtpm); |
276 | tasklet_kill(&ibmvtpm->tasklet); | ||
277 | 276 | ||
278 | do { | 277 | do { |
279 | if (rc) | 278 | if (rc) |
@@ -372,7 +371,6 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm) | |||
372 | static int tpm_ibmvtpm_resume(struct device *dev) | 371 | static int tpm_ibmvtpm_resume(struct device *dev) |
373 | { | 372 | { |
374 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev); | 373 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev); |
375 | unsigned long flags; | ||
376 | int rc = 0; | 374 | int rc = 0; |
377 | 375 | ||
378 | do { | 376 | do { |
@@ -387,10 +385,11 @@ static int tpm_ibmvtpm_resume(struct device *dev) | |||
387 | return rc; | 385 | return rc; |
388 | } | 386 | } |
389 | 387 | ||
390 | spin_lock_irqsave(&ibmvtpm->lock, flags); | 388 | rc = vio_enable_interrupts(ibmvtpm->vdev); |
391 | vio_disable_interrupts(ibmvtpm->vdev); | 389 | if (rc) { |
392 | tasklet_schedule(&ibmvtpm->tasklet); | 390 | dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc); |
393 | spin_unlock_irqrestore(&ibmvtpm->lock, flags); | 391 | return rc; |
392 | } | ||
394 | 393 | ||
395 | rc = ibmvtpm_crq_send_init(ibmvtpm); | 394 | rc = ibmvtpm_crq_send_init(ibmvtpm); |
396 | if (rc) | 395 | if (rc) |
@@ -467,7 +466,7 @@ static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm) | |||
467 | if (crq->valid & VTPM_MSG_RES) { | 466 | if (crq->valid & VTPM_MSG_RES) { |
468 | if (++crq_q->index == crq_q->num_entry) | 467 | if (++crq_q->index == crq_q->num_entry) |
469 | crq_q->index = 0; | 468 | crq_q->index = 0; |
470 | rmb(); | 469 | smp_rmb(); |
471 | } else | 470 | } else |
472 | crq = NULL; | 471 | crq = NULL; |
473 | return crq; | 472 | return crq; |
@@ -535,11 +534,9 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, | |||
535 | ibmvtpm->vtpm_version = crq->data; | 534 | ibmvtpm->vtpm_version = crq->data; |
536 | return; | 535 | return; |
537 | case VTPM_TPM_COMMAND_RES: | 536 | case VTPM_TPM_COMMAND_RES: |
538 | ibmvtpm->crq_res.valid = crq->valid; | 537 | /* len of the data in rtce buffer */ |
539 | ibmvtpm->crq_res.msg = crq->msg; | 538 | ibmvtpm->res_len = crq->len; |
540 | ibmvtpm->crq_res.len = crq->len; | 539 | wake_up_interruptible(&ibmvtpm->wq); |
541 | ibmvtpm->crq_res.data = crq->data; | ||
542 | wake_up_interruptible(&wq); | ||
543 | return; | 540 | return; |
544 | default: | 541 | default: |
545 | return; | 542 | return; |
@@ -559,38 +556,19 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, | |||
559 | static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance) | 556 | static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance) |
560 | { | 557 | { |
561 | struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance; | 558 | struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance; |
562 | unsigned long flags; | ||
563 | |||
564 | spin_lock_irqsave(&ibmvtpm->lock, flags); | ||
565 | vio_disable_interrupts(ibmvtpm->vdev); | ||
566 | tasklet_schedule(&ibmvtpm->tasklet); | ||
567 | spin_unlock_irqrestore(&ibmvtpm->lock, flags); | ||
568 | |||
569 | return IRQ_HANDLED; | ||
570 | } | ||
571 | |||
572 | /** | ||
573 | * ibmvtpm_tasklet - Interrupt handler tasklet | ||
574 | * @data: ibm vtpm device struct | ||
575 | * | ||
576 | * Returns: | ||
577 | * Nothing | ||
578 | **/ | ||
579 | static void ibmvtpm_tasklet(void *data) | ||
580 | { | ||
581 | struct ibmvtpm_dev *ibmvtpm = data; | ||
582 | struct ibmvtpm_crq *crq; | 559 | struct ibmvtpm_crq *crq; |
583 | unsigned long flags; | ||
584 | 560 | ||
585 | spin_lock_irqsave(&ibmvtpm->lock, flags); | 561 | /* while loop is needed for initial setup (get version and |
562 | * get rtce_size). There should be only one tpm request at any | ||
563 | * given time. | ||
564 | */ | ||
586 | while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) { | 565 | while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) { |
587 | ibmvtpm_crq_process(crq, ibmvtpm); | 566 | ibmvtpm_crq_process(crq, ibmvtpm); |
588 | crq->valid = 0; | 567 | crq->valid = 0; |
589 | wmb(); | 568 | smp_wmb(); |
590 | } | 569 | } |
591 | 570 | ||
592 | vio_enable_interrupts(ibmvtpm->vdev); | 571 | return IRQ_HANDLED; |
593 | spin_unlock_irqrestore(&ibmvtpm->lock, flags); | ||
594 | } | 572 | } |
595 | 573 | ||
596 | /** | 574 | /** |
@@ -650,9 +628,6 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, | |||
650 | goto reg_crq_cleanup; | 628 | goto reg_crq_cleanup; |
651 | } | 629 | } |
652 | 630 | ||
653 | tasklet_init(&ibmvtpm->tasklet, (void *)ibmvtpm_tasklet, | ||
654 | (unsigned long)ibmvtpm); | ||
655 | |||
656 | rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0, | 631 | rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0, |
657 | tpm_ibmvtpm_driver_name, ibmvtpm); | 632 | tpm_ibmvtpm_driver_name, ibmvtpm); |
658 | if (rc) { | 633 | if (rc) { |
@@ -666,13 +641,14 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, | |||
666 | goto init_irq_cleanup; | 641 | goto init_irq_cleanup; |
667 | } | 642 | } |
668 | 643 | ||
644 | init_waitqueue_head(&ibmvtpm->wq); | ||
645 | |||
669 | crq_q->index = 0; | 646 | crq_q->index = 0; |
670 | 647 | ||
671 | ibmvtpm->dev = dev; | 648 | ibmvtpm->dev = dev; |
672 | ibmvtpm->vdev = vio_dev; | 649 | ibmvtpm->vdev = vio_dev; |
673 | chip->vendor.data = (void *)ibmvtpm; | 650 | chip->vendor.data = (void *)ibmvtpm; |
674 | 651 | ||
675 | spin_lock_init(&ibmvtpm->lock); | ||
676 | spin_lock_init(&ibmvtpm->rtce_lock); | 652 | spin_lock_init(&ibmvtpm->rtce_lock); |
677 | 653 | ||
678 | rc = ibmvtpm_crq_send_init(ibmvtpm); | 654 | rc = ibmvtpm_crq_send_init(ibmvtpm); |
@@ -689,7 +665,6 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, | |||
689 | 665 | ||
690 | return rc; | 666 | return rc; |
691 | init_irq_cleanup: | 667 | init_irq_cleanup: |
692 | tasklet_kill(&ibmvtpm->tasklet); | ||
693 | do { | 668 | do { |
694 | rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address); | 669 | rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address); |
695 | } while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1)); | 670 | } while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1)); |
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h index 4296eb4b4d82..bd82a791f995 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.h +++ b/drivers/char/tpm/tpm_ibmvtpm.h | |||
@@ -38,13 +38,12 @@ struct ibmvtpm_dev { | |||
38 | struct vio_dev *vdev; | 38 | struct vio_dev *vdev; |
39 | struct ibmvtpm_crq_queue crq_queue; | 39 | struct ibmvtpm_crq_queue crq_queue; |
40 | dma_addr_t crq_dma_handle; | 40 | dma_addr_t crq_dma_handle; |
41 | spinlock_t lock; | ||
42 | struct tasklet_struct tasklet; | ||
43 | u32 rtce_size; | 41 | u32 rtce_size; |
44 | void __iomem *rtce_buf; | 42 | void __iomem *rtce_buf; |
45 | dma_addr_t rtce_dma_handle; | 43 | dma_addr_t rtce_dma_handle; |
46 | spinlock_t rtce_lock; | 44 | spinlock_t rtce_lock; |
47 | struct ibmvtpm_crq crq_res; | 45 | wait_queue_head_t wq; |
46 | u16 res_len; | ||
48 | u32 vtpm_version; | 47 | u32 vtpm_version; |
49 | }; | 48 | }; |
50 | 49 | ||
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 75c1ee699143..5cbd00e74067 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -346,19 +346,15 @@ init_cifs_idmap(void) | |||
346 | if (!cred) | 346 | if (!cred) |
347 | return -ENOMEM; | 347 | return -ENOMEM; |
348 | 348 | ||
349 | keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred, | 349 | keyring = keyring_alloc(".cifs_idmap", 0, 0, cred, |
350 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 350 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
351 | KEY_USR_VIEW | KEY_USR_READ, | 351 | KEY_USR_VIEW | KEY_USR_READ, |
352 | KEY_ALLOC_NOT_IN_QUOTA); | 352 | KEY_ALLOC_NOT_IN_QUOTA, NULL); |
353 | if (IS_ERR(keyring)) { | 353 | if (IS_ERR(keyring)) { |
354 | ret = PTR_ERR(keyring); | 354 | ret = PTR_ERR(keyring); |
355 | goto failed_put_cred; | 355 | goto failed_put_cred; |
356 | } | 356 | } |
357 | 357 | ||
358 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | ||
359 | if (ret < 0) | ||
360 | goto failed_put_key; | ||
361 | |||
362 | ret = register_key_type(&cifs_idmap_key_type); | 358 | ret = register_key_type(&cifs_idmap_key_type); |
363 | if (ret < 0) | 359 | if (ret < 0) |
364 | goto failed_put_key; | 360 | goto failed_put_key; |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 9cc4a3fbf4b0..bc3968fa81e5 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -193,19 +193,15 @@ static int nfs_idmap_init_keyring(void) | |||
193 | if (!cred) | 193 | if (!cred) |
194 | return -ENOMEM; | 194 | return -ENOMEM; |
195 | 195 | ||
196 | keyring = key_alloc(&key_type_keyring, ".id_resolver", 0, 0, cred, | 196 | keyring = keyring_alloc(".id_resolver", 0, 0, cred, |
197 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 197 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
198 | KEY_USR_VIEW | KEY_USR_READ, | 198 | KEY_USR_VIEW | KEY_USR_READ, |
199 | KEY_ALLOC_NOT_IN_QUOTA); | 199 | KEY_ALLOC_NOT_IN_QUOTA, NULL); |
200 | if (IS_ERR(keyring)) { | 200 | if (IS_ERR(keyring)) { |
201 | ret = PTR_ERR(keyring); | 201 | ret = PTR_ERR(keyring); |
202 | goto failed_put_cred; | 202 | goto failed_put_cred; |
203 | } | 203 | } |
204 | 204 | ||
205 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | ||
206 | if (ret < 0) | ||
207 | goto failed_put_key; | ||
208 | |||
209 | ret = register_key_type(&key_type_id_resolver); | 205 | ret = register_key_type(&key_type_id_resolver); |
210 | if (ret < 0) | 206 | if (ret < 0) |
211 | goto failed_put_key; | 207 | goto failed_put_key; |
diff --git a/include/linux/cred.h b/include/linux/cred.h index ebbed2ce6637..0142aacb70b7 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
@@ -77,21 +77,6 @@ extern int in_group_p(kgid_t); | |||
77 | extern int in_egroup_p(kgid_t); | 77 | extern int in_egroup_p(kgid_t); |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * The common credentials for a thread group | ||
81 | * - shared by CLONE_THREAD | ||
82 | */ | ||
83 | #ifdef CONFIG_KEYS | ||
84 | struct thread_group_cred { | ||
85 | atomic_t usage; | ||
86 | pid_t tgid; /* thread group process ID */ | ||
87 | spinlock_t lock; | ||
88 | struct key __rcu *session_keyring; /* keyring inherited over fork */ | ||
89 | struct key *process_keyring; /* keyring private to this process */ | ||
90 | struct rcu_head rcu; /* RCU deletion hook */ | ||
91 | }; | ||
92 | #endif | ||
93 | |||
94 | /* | ||
95 | * The security context of a task | 80 | * The security context of a task |
96 | * | 81 | * |
97 | * The parts of the context break down into two categories: | 82 | * The parts of the context break down into two categories: |
@@ -139,6 +124,8 @@ struct cred { | |||
139 | #ifdef CONFIG_KEYS | 124 | #ifdef CONFIG_KEYS |
140 | unsigned char jit_keyring; /* default keyring to attach requested | 125 | unsigned char jit_keyring; /* default keyring to attach requested |
141 | * keys to */ | 126 | * keys to */ |
127 | struct key __rcu *session_keyring; /* keyring inherited over fork */ | ||
128 | struct key *process_keyring; /* keyring private to this process */ | ||
142 | struct key *thread_keyring; /* keyring private to this thread */ | 129 | struct key *thread_keyring; /* keyring private to this thread */ |
143 | struct key *request_key_auth; /* assumed request_key authority */ | 130 | struct key *request_key_auth; /* assumed request_key authority */ |
144 | struct thread_group_cred *tgcred; /* thread-group shared credentials */ | 131 | struct thread_group_cred *tgcred; /* thread-group shared credentials */ |
diff --git a/include/linux/key.h b/include/linux/key.h index 2393b1c040b6..4dfde1161c5e 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -265,6 +265,7 @@ extern int key_unlink(struct key *keyring, | |||
265 | 265 | ||
266 | extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, | 266 | extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, |
267 | const struct cred *cred, | 267 | const struct cred *cred, |
268 | key_perm_t perm, | ||
268 | unsigned long flags, | 269 | unsigned long flags, |
269 | struct key *dest); | 270 | struct key *dest); |
270 | 271 | ||
diff --git a/kernel/cred.c b/kernel/cred.c index 48cea3da6d05..8888afb846e9 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
@@ -30,17 +30,6 @@ | |||
30 | static struct kmem_cache *cred_jar; | 30 | static struct kmem_cache *cred_jar; |
31 | 31 | ||
32 | /* | 32 | /* |
33 | * The common credentials for the initial task's thread group | ||
34 | */ | ||
35 | #ifdef CONFIG_KEYS | ||
36 | static struct thread_group_cred init_tgcred = { | ||
37 | .usage = ATOMIC_INIT(2), | ||
38 | .tgid = 0, | ||
39 | .lock = __SPIN_LOCK_UNLOCKED(init_cred.tgcred.lock), | ||
40 | }; | ||
41 | #endif | ||
42 | |||
43 | /* | ||
44 | * The initial credentials for the initial task | 33 | * The initial credentials for the initial task |
45 | */ | 34 | */ |
46 | struct cred init_cred = { | 35 | struct cred init_cred = { |
@@ -65,9 +54,6 @@ struct cred init_cred = { | |||
65 | .user = INIT_USER, | 54 | .user = INIT_USER, |
66 | .user_ns = &init_user_ns, | 55 | .user_ns = &init_user_ns, |
67 | .group_info = &init_groups, | 56 | .group_info = &init_groups, |
68 | #ifdef CONFIG_KEYS | ||
69 | .tgcred = &init_tgcred, | ||
70 | #endif | ||
71 | }; | 57 | }; |
72 | 58 | ||
73 | static inline void set_cred_subscribers(struct cred *cred, int n) | 59 | static inline void set_cred_subscribers(struct cred *cred, int n) |
@@ -96,36 +82,6 @@ static inline void alter_cred_subscribers(const struct cred *_cred, int n) | |||
96 | } | 82 | } |
97 | 83 | ||
98 | /* | 84 | /* |
99 | * Dispose of the shared task group credentials | ||
100 | */ | ||
101 | #ifdef CONFIG_KEYS | ||
102 | static void release_tgcred_rcu(struct rcu_head *rcu) | ||
103 | { | ||
104 | struct thread_group_cred *tgcred = | ||
105 | container_of(rcu, struct thread_group_cred, rcu); | ||
106 | |||
107 | BUG_ON(atomic_read(&tgcred->usage) != 0); | ||
108 | |||
109 | key_put(tgcred->session_keyring); | ||
110 | key_put(tgcred->process_keyring); | ||
111 | kfree(tgcred); | ||
112 | } | ||
113 | #endif | ||
114 | |||
115 | /* | ||
116 | * Release a set of thread group credentials. | ||
117 | */ | ||
118 | static void release_tgcred(struct cred *cred) | ||
119 | { | ||
120 | #ifdef CONFIG_KEYS | ||
121 | struct thread_group_cred *tgcred = cred->tgcred; | ||
122 | |||
123 | if (atomic_dec_and_test(&tgcred->usage)) | ||
124 | call_rcu(&tgcred->rcu, release_tgcred_rcu); | ||
125 | #endif | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * The RCU callback to actually dispose of a set of credentials | 85 | * The RCU callback to actually dispose of a set of credentials |
130 | */ | 86 | */ |
131 | static void put_cred_rcu(struct rcu_head *rcu) | 87 | static void put_cred_rcu(struct rcu_head *rcu) |
@@ -150,9 +106,10 @@ static void put_cred_rcu(struct rcu_head *rcu) | |||
150 | #endif | 106 | #endif |
151 | 107 | ||
152 | security_cred_free(cred); | 108 | security_cred_free(cred); |
109 | key_put(cred->session_keyring); | ||
110 | key_put(cred->process_keyring); | ||
153 | key_put(cred->thread_keyring); | 111 | key_put(cred->thread_keyring); |
154 | key_put(cred->request_key_auth); | 112 | key_put(cred->request_key_auth); |
155 | release_tgcred(cred); | ||
156 | if (cred->group_info) | 113 | if (cred->group_info) |
157 | put_group_info(cred->group_info); | 114 | put_group_info(cred->group_info); |
158 | free_uid(cred->user); | 115 | free_uid(cred->user); |
@@ -246,15 +203,6 @@ struct cred *cred_alloc_blank(void) | |||
246 | if (!new) | 203 | if (!new) |
247 | return NULL; | 204 | return NULL; |
248 | 205 | ||
249 | #ifdef CONFIG_KEYS | ||
250 | new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL); | ||
251 | if (!new->tgcred) { | ||
252 | kmem_cache_free(cred_jar, new); | ||
253 | return NULL; | ||
254 | } | ||
255 | atomic_set(&new->tgcred->usage, 1); | ||
256 | #endif | ||
257 | |||
258 | atomic_set(&new->usage, 1); | 206 | atomic_set(&new->usage, 1); |
259 | #ifdef CONFIG_DEBUG_CREDENTIALS | 207 | #ifdef CONFIG_DEBUG_CREDENTIALS |
260 | new->magic = CRED_MAGIC; | 208 | new->magic = CRED_MAGIC; |
@@ -308,9 +256,10 @@ struct cred *prepare_creds(void) | |||
308 | get_user_ns(new->user_ns); | 256 | get_user_ns(new->user_ns); |
309 | 257 | ||
310 | #ifdef CONFIG_KEYS | 258 | #ifdef CONFIG_KEYS |
259 | key_get(new->session_keyring); | ||
260 | key_get(new->process_keyring); | ||
311 | key_get(new->thread_keyring); | 261 | key_get(new->thread_keyring); |
312 | key_get(new->request_key_auth); | 262 | key_get(new->request_key_auth); |
313 | atomic_inc(&new->tgcred->usage); | ||
314 | #endif | 263 | #endif |
315 | 264 | ||
316 | #ifdef CONFIG_SECURITY | 265 | #ifdef CONFIG_SECURITY |
@@ -334,39 +283,20 @@ EXPORT_SYMBOL(prepare_creds); | |||
334 | */ | 283 | */ |
335 | struct cred *prepare_exec_creds(void) | 284 | struct cred *prepare_exec_creds(void) |
336 | { | 285 | { |
337 | struct thread_group_cred *tgcred = NULL; | ||
338 | struct cred *new; | 286 | struct cred *new; |
339 | 287 | ||
340 | #ifdef CONFIG_KEYS | ||
341 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | ||
342 | if (!tgcred) | ||
343 | return NULL; | ||
344 | #endif | ||
345 | |||
346 | new = prepare_creds(); | 288 | new = prepare_creds(); |
347 | if (!new) { | 289 | if (!new) |
348 | kfree(tgcred); | ||
349 | return new; | 290 | return new; |
350 | } | ||
351 | 291 | ||
352 | #ifdef CONFIG_KEYS | 292 | #ifdef CONFIG_KEYS |
353 | /* newly exec'd tasks don't get a thread keyring */ | 293 | /* newly exec'd tasks don't get a thread keyring */ |
354 | key_put(new->thread_keyring); | 294 | key_put(new->thread_keyring); |
355 | new->thread_keyring = NULL; | 295 | new->thread_keyring = NULL; |
356 | 296 | ||
357 | /* create a new per-thread-group creds for all this set of threads to | ||
358 | * share */ | ||
359 | memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred)); | ||
360 | |||
361 | atomic_set(&tgcred->usage, 1); | ||
362 | spin_lock_init(&tgcred->lock); | ||
363 | |||
364 | /* inherit the session keyring; new process keyring */ | 297 | /* inherit the session keyring; new process keyring */ |
365 | key_get(tgcred->session_keyring); | 298 | key_put(new->process_keyring); |
366 | tgcred->process_keyring = NULL; | 299 | new->process_keyring = NULL; |
367 | |||
368 | release_tgcred(new); | ||
369 | new->tgcred = tgcred; | ||
370 | #endif | 300 | #endif |
371 | 301 | ||
372 | return new; | 302 | return new; |
@@ -383,9 +313,6 @@ struct cred *prepare_exec_creds(void) | |||
383 | */ | 313 | */ |
384 | int copy_creds(struct task_struct *p, unsigned long clone_flags) | 314 | int copy_creds(struct task_struct *p, unsigned long clone_flags) |
385 | { | 315 | { |
386 | #ifdef CONFIG_KEYS | ||
387 | struct thread_group_cred *tgcred; | ||
388 | #endif | ||
389 | struct cred *new; | 316 | struct cred *new; |
390 | int ret; | 317 | int ret; |
391 | 318 | ||
@@ -425,22 +352,12 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
425 | install_thread_keyring_to_cred(new); | 352 | install_thread_keyring_to_cred(new); |
426 | } | 353 | } |
427 | 354 | ||
428 | /* we share the process and session keyrings between all the threads in | 355 | /* The process keyring is only shared between the threads in a process; |
429 | * a process - this is slightly icky as we violate COW credentials a | 356 | * anything outside of those threads doesn't inherit. |
430 | * bit */ | 357 | */ |
431 | if (!(clone_flags & CLONE_THREAD)) { | 358 | if (!(clone_flags & CLONE_THREAD)) { |
432 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | 359 | key_put(new->process_keyring); |
433 | if (!tgcred) { | 360 | new->process_keyring = NULL; |
434 | ret = -ENOMEM; | ||
435 | goto error_put; | ||
436 | } | ||
437 | atomic_set(&tgcred->usage, 1); | ||
438 | spin_lock_init(&tgcred->lock); | ||
439 | tgcred->process_keyring = NULL; | ||
440 | tgcred->session_keyring = key_get(new->tgcred->session_keyring); | ||
441 | |||
442 | release_tgcred(new); | ||
443 | new->tgcred = tgcred; | ||
444 | } | 361 | } |
445 | #endif | 362 | #endif |
446 | 363 | ||
@@ -643,9 +560,6 @@ void __init cred_init(void) | |||
643 | */ | 560 | */ |
644 | struct cred *prepare_kernel_cred(struct task_struct *daemon) | 561 | struct cred *prepare_kernel_cred(struct task_struct *daemon) |
645 | { | 562 | { |
646 | #ifdef CONFIG_KEYS | ||
647 | struct thread_group_cred *tgcred; | ||
648 | #endif | ||
649 | const struct cred *old; | 563 | const struct cred *old; |
650 | struct cred *new; | 564 | struct cred *new; |
651 | 565 | ||
@@ -653,14 +567,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
653 | if (!new) | 567 | if (!new) |
654 | return NULL; | 568 | return NULL; |
655 | 569 | ||
656 | #ifdef CONFIG_KEYS | ||
657 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | ||
658 | if (!tgcred) { | ||
659 | kmem_cache_free(cred_jar, new); | ||
660 | return NULL; | ||
661 | } | ||
662 | #endif | ||
663 | |||
664 | kdebug("prepare_kernel_cred() alloc %p", new); | 570 | kdebug("prepare_kernel_cred() alloc %p", new); |
665 | 571 | ||
666 | if (daemon) | 572 | if (daemon) |
@@ -678,13 +584,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
678 | get_group_info(new->group_info); | 584 | get_group_info(new->group_info); |
679 | 585 | ||
680 | #ifdef CONFIG_KEYS | 586 | #ifdef CONFIG_KEYS |
681 | atomic_set(&tgcred->usage, 1); | 587 | new->session_keyring = NULL; |
682 | spin_lock_init(&tgcred->lock); | 588 | new->process_keyring = NULL; |
683 | tgcred->process_keyring = NULL; | ||
684 | tgcred->session_keyring = NULL; | ||
685 | new->tgcred = tgcred; | ||
686 | new->request_key_auth = NULL; | ||
687 | new->thread_keyring = NULL; | 589 | new->thread_keyring = NULL; |
590 | new->request_key_auth = NULL; | ||
688 | new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | 591 | new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; |
689 | #endif | 592 | #endif |
690 | 593 | ||
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index ee376beedaf9..5af44b593770 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -396,25 +396,29 @@ int __secure_computing(int this_syscall) | |||
396 | #ifdef CONFIG_SECCOMP_FILTER | 396 | #ifdef CONFIG_SECCOMP_FILTER |
397 | case SECCOMP_MODE_FILTER: { | 397 | case SECCOMP_MODE_FILTER: { |
398 | int data; | 398 | int data; |
399 | struct pt_regs *regs = task_pt_regs(current); | ||
399 | ret = seccomp_run_filters(this_syscall); | 400 | ret = seccomp_run_filters(this_syscall); |
400 | data = ret & SECCOMP_RET_DATA; | 401 | data = ret & SECCOMP_RET_DATA; |
401 | ret &= SECCOMP_RET_ACTION; | 402 | ret &= SECCOMP_RET_ACTION; |
402 | switch (ret) { | 403 | switch (ret) { |
403 | case SECCOMP_RET_ERRNO: | 404 | case SECCOMP_RET_ERRNO: |
404 | /* Set the low-order 16-bits as a errno. */ | 405 | /* Set the low-order 16-bits as a errno. */ |
405 | syscall_set_return_value(current, task_pt_regs(current), | 406 | syscall_set_return_value(current, regs, |
406 | -data, 0); | 407 | -data, 0); |
407 | goto skip; | 408 | goto skip; |
408 | case SECCOMP_RET_TRAP: | 409 | case SECCOMP_RET_TRAP: |
409 | /* Show the handler the original registers. */ | 410 | /* Show the handler the original registers. */ |
410 | syscall_rollback(current, task_pt_regs(current)); | 411 | syscall_rollback(current, regs); |
411 | /* Let the filter pass back 16 bits of data. */ | 412 | /* Let the filter pass back 16 bits of data. */ |
412 | seccomp_send_sigsys(this_syscall, data); | 413 | seccomp_send_sigsys(this_syscall, data); |
413 | goto skip; | 414 | goto skip; |
414 | case SECCOMP_RET_TRACE: | 415 | case SECCOMP_RET_TRACE: |
415 | /* Skip these calls if there is no tracer. */ | 416 | /* Skip these calls if there is no tracer. */ |
416 | if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) | 417 | if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) { |
418 | syscall_set_return_value(current, regs, | ||
419 | -ENOSYS, 0); | ||
417 | goto skip; | 420 | goto skip; |
421 | } | ||
418 | /* Allow the BPF to provide the event message */ | 422 | /* Allow the BPF to provide the event message */ |
419 | ptrace_event(PTRACE_EVENT_SECCOMP, data); | 423 | ptrace_event(PTRACE_EVENT_SECCOMP, data); |
420 | /* | 424 | /* |
@@ -425,6 +429,9 @@ int __secure_computing(int this_syscall) | |||
425 | */ | 429 | */ |
426 | if (fatal_signal_pending(current)) | 430 | if (fatal_signal_pending(current)) |
427 | break; | 431 | break; |
432 | if (syscall_get_nr(current, regs) < 0) | ||
433 | goto skip; /* Explicit request to skip. */ | ||
434 | |||
428 | return 0; | 435 | return 0; |
429 | case SECCOMP_RET_ALLOW: | 436 | case SECCOMP_RET_ALLOW: |
430 | return 0; | 437 | return 0; |
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index 8aa4b1115384..0a69d0757795 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c | |||
@@ -259,20 +259,16 @@ static int __init init_dns_resolver(void) | |||
259 | if (!cred) | 259 | if (!cred) |
260 | return -ENOMEM; | 260 | return -ENOMEM; |
261 | 261 | ||
262 | keyring = key_alloc(&key_type_keyring, ".dns_resolver", | 262 | keyring = keyring_alloc(".dns_resolver", |
263 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, | 263 | GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, |
264 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 264 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
265 | KEY_USR_VIEW | KEY_USR_READ, | 265 | KEY_USR_VIEW | KEY_USR_READ, |
266 | KEY_ALLOC_NOT_IN_QUOTA); | 266 | KEY_ALLOC_NOT_IN_QUOTA, NULL); |
267 | if (IS_ERR(keyring)) { | 267 | if (IS_ERR(keyring)) { |
268 | ret = PTR_ERR(keyring); | 268 | ret = PTR_ERR(keyring); |
269 | goto failed_put_cred; | 269 | goto failed_put_cred; |
270 | } | 270 | } |
271 | 271 | ||
272 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | ||
273 | if (ret < 0) | ||
274 | goto failed_put_key; | ||
275 | |||
276 | ret = register_key_type(&key_type_dns_resolver); | 272 | ret = register_key_type(&key_type_dns_resolver); |
277 | if (ret < 0) | 273 | if (ret < 0) |
278 | goto failed_put_key; | 274 | goto failed_put_key; |
@@ -304,3 +300,4 @@ static void __exit exit_dns_resolver(void) | |||
304 | module_init(init_dns_resolver) | 300 | module_init(init_dns_resolver) |
305 | module_exit(exit_dns_resolver) | 301 | module_exit(exit_dns_resolver) |
306 | MODULE_LICENSE("GPL"); | 302 | MODULE_LICENSE("GPL"); |
303 | |||
diff --git a/security/keys/key.c b/security/keys/key.c index a15c9da8f971..8fb7c7bd4657 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -854,13 +854,13 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
854 | /* if the client doesn't provide, decide on the permissions we want */ | 854 | /* if the client doesn't provide, decide on the permissions we want */ |
855 | if (perm == KEY_PERM_UNDEF) { | 855 | if (perm == KEY_PERM_UNDEF) { |
856 | perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; | 856 | perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; |
857 | perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR; | 857 | perm |= KEY_USR_VIEW; |
858 | 858 | ||
859 | if (ktype->read) | 859 | if (ktype->read) |
860 | perm |= KEY_POS_READ | KEY_USR_READ; | 860 | perm |= KEY_POS_READ; |
861 | 861 | ||
862 | if (ktype == &key_type_keyring || ktype->update) | 862 | if (ktype == &key_type_keyring || ktype->update) |
863 | perm |= KEY_USR_WRITE; | 863 | perm |= KEY_POS_WRITE; |
864 | } | 864 | } |
865 | 865 | ||
866 | /* allocate a new key */ | 866 | /* allocate a new key */ |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 5d34b4e827d6..4b5c948eb414 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -1132,12 +1132,12 @@ long keyctl_instantiate_key_iov(key_serial_t id, | |||
1132 | ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, | 1132 | ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc, |
1133 | ARRAY_SIZE(iovstack), iovstack, &iov); | 1133 | ARRAY_SIZE(iovstack), iovstack, &iov); |
1134 | if (ret < 0) | 1134 | if (ret < 0) |
1135 | return ret; | 1135 | goto err; |
1136 | if (ret == 0) | 1136 | if (ret == 0) |
1137 | goto no_payload_free; | 1137 | goto no_payload_free; |
1138 | 1138 | ||
1139 | ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); | 1139 | ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid); |
1140 | 1140 | err: | |
1141 | if (iov != iovstack) | 1141 | if (iov != iovstack) |
1142 | kfree(iov); | 1142 | kfree(iov); |
1143 | return ret; | 1143 | return ret; |
@@ -1495,7 +1495,8 @@ long keyctl_session_to_parent(void) | |||
1495 | goto error_keyring; | 1495 | goto error_keyring; |
1496 | newwork = &cred->rcu; | 1496 | newwork = &cred->rcu; |
1497 | 1497 | ||
1498 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | 1498 | cred->session_keyring = key_ref_to_ptr(keyring_r); |
1499 | keyring_r = NULL; | ||
1499 | init_task_work(newwork, key_change_session_keyring); | 1500 | init_task_work(newwork, key_change_session_keyring); |
1500 | 1501 | ||
1501 | me = current; | 1502 | me = current; |
@@ -1519,7 +1520,7 @@ long keyctl_session_to_parent(void) | |||
1519 | mycred = current_cred(); | 1520 | mycred = current_cred(); |
1520 | pcred = __task_cred(parent); | 1521 | pcred = __task_cred(parent); |
1521 | if (mycred == pcred || | 1522 | if (mycred == pcred || |
1522 | mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) { | 1523 | mycred->session_keyring == pcred->session_keyring) { |
1523 | ret = 0; | 1524 | ret = 0; |
1524 | goto unlock; | 1525 | goto unlock; |
1525 | } | 1526 | } |
@@ -1535,9 +1536,9 @@ long keyctl_session_to_parent(void) | |||
1535 | goto unlock; | 1536 | goto unlock; |
1536 | 1537 | ||
1537 | /* the keyrings must have the same UID */ | 1538 | /* the keyrings must have the same UID */ |
1538 | if ((pcred->tgcred->session_keyring && | 1539 | if ((pcred->session_keyring && |
1539 | !uid_eq(pcred->tgcred->session_keyring->uid, mycred->euid)) || | 1540 | !uid_eq(pcred->session_keyring->uid, mycred->euid)) || |
1540 | !uid_eq(mycred->tgcred->session_keyring->uid, mycred->euid)) | 1541 | !uid_eq(mycred->session_keyring->uid, mycred->euid)) |
1541 | goto unlock; | 1542 | goto unlock; |
1542 | 1543 | ||
1543 | /* cancel an already pending keyring replacement */ | 1544 | /* cancel an already pending keyring replacement */ |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 6e42df15a24c..6ece7f2e5707 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -257,17 +257,14 @@ error: | |||
257 | * Allocate a keyring and link into the destination keyring. | 257 | * Allocate a keyring and link into the destination keyring. |
258 | */ | 258 | */ |
259 | struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, | 259 | struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, |
260 | const struct cred *cred, unsigned long flags, | 260 | const struct cred *cred, key_perm_t perm, |
261 | struct key *dest) | 261 | unsigned long flags, struct key *dest) |
262 | { | 262 | { |
263 | struct key *keyring; | 263 | struct key *keyring; |
264 | int ret; | 264 | int ret; |
265 | 265 | ||
266 | keyring = key_alloc(&key_type_keyring, description, | 266 | keyring = key_alloc(&key_type_keyring, description, |
267 | uid, gid, cred, | 267 | uid, gid, cred, perm, flags); |
268 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | ||
269 | flags); | ||
270 | |||
271 | if (!IS_ERR(keyring)) { | 268 | if (!IS_ERR(keyring)) { |
272 | ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); | 269 | ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); |
273 | if (ret < 0) { | 270 | if (ret < 0) { |
@@ -278,6 +275,7 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, | |||
278 | 275 | ||
279 | return keyring; | 276 | return keyring; |
280 | } | 277 | } |
278 | EXPORT_SYMBOL(keyring_alloc); | ||
281 | 279 | ||
282 | /** | 280 | /** |
283 | * keyring_search_aux - Search a keyring tree for a key matching some criteria | 281 | * keyring_search_aux - Search a keyring tree for a key matching some criteria |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 86468f385fc8..58dfe0890947 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -45,10 +45,12 @@ int install_user_keyrings(void) | |||
45 | struct user_struct *user; | 45 | struct user_struct *user; |
46 | const struct cred *cred; | 46 | const struct cred *cred; |
47 | struct key *uid_keyring, *session_keyring; | 47 | struct key *uid_keyring, *session_keyring; |
48 | key_perm_t user_keyring_perm; | ||
48 | char buf[20]; | 49 | char buf[20]; |
49 | int ret; | 50 | int ret; |
50 | uid_t uid; | 51 | uid_t uid; |
51 | 52 | ||
53 | user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL; | ||
52 | cred = current_cred(); | 54 | cred = current_cred(); |
53 | user = cred->user; | 55 | user = cred->user; |
54 | uid = from_kuid(cred->user_ns, user->uid); | 56 | uid = from_kuid(cred->user_ns, user->uid); |
@@ -73,8 +75,8 @@ int install_user_keyrings(void) | |||
73 | uid_keyring = find_keyring_by_name(buf, true); | 75 | uid_keyring = find_keyring_by_name(buf, true); |
74 | if (IS_ERR(uid_keyring)) { | 76 | if (IS_ERR(uid_keyring)) { |
75 | uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, | 77 | uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, |
76 | cred, KEY_ALLOC_IN_QUOTA, | 78 | cred, user_keyring_perm, |
77 | NULL); | 79 | KEY_ALLOC_IN_QUOTA, NULL); |
78 | if (IS_ERR(uid_keyring)) { | 80 | if (IS_ERR(uid_keyring)) { |
79 | ret = PTR_ERR(uid_keyring); | 81 | ret = PTR_ERR(uid_keyring); |
80 | goto error; | 82 | goto error; |
@@ -89,7 +91,8 @@ int install_user_keyrings(void) | |||
89 | if (IS_ERR(session_keyring)) { | 91 | if (IS_ERR(session_keyring)) { |
90 | session_keyring = | 92 | session_keyring = |
91 | keyring_alloc(buf, user->uid, INVALID_GID, | 93 | keyring_alloc(buf, user->uid, INVALID_GID, |
92 | cred, KEY_ALLOC_IN_QUOTA, NULL); | 94 | cred, user_keyring_perm, |
95 | KEY_ALLOC_IN_QUOTA, NULL); | ||
93 | if (IS_ERR(session_keyring)) { | 96 | if (IS_ERR(session_keyring)) { |
94 | ret = PTR_ERR(session_keyring); | 97 | ret = PTR_ERR(session_keyring); |
95 | goto error_release; | 98 | goto error_release; |
@@ -130,6 +133,7 @@ int install_thread_keyring_to_cred(struct cred *new) | |||
130 | struct key *keyring; | 133 | struct key *keyring; |
131 | 134 | ||
132 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, | 135 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, |
136 | KEY_POS_ALL | KEY_USR_VIEW, | ||
133 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 137 | KEY_ALLOC_QUOTA_OVERRUN, NULL); |
134 | if (IS_ERR(keyring)) | 138 | if (IS_ERR(keyring)) |
135 | return PTR_ERR(keyring); | 139 | return PTR_ERR(keyring); |
@@ -170,27 +174,18 @@ static int install_thread_keyring(void) | |||
170 | int install_process_keyring_to_cred(struct cred *new) | 174 | int install_process_keyring_to_cred(struct cred *new) |
171 | { | 175 | { |
172 | struct key *keyring; | 176 | struct key *keyring; |
173 | int ret; | ||
174 | 177 | ||
175 | if (new->tgcred->process_keyring) | 178 | if (new->process_keyring) |
176 | return -EEXIST; | 179 | return -EEXIST; |
177 | 180 | ||
178 | keyring = keyring_alloc("_pid", new->uid, new->gid, | 181 | keyring = keyring_alloc("_pid", new->uid, new->gid, new, |
179 | new, KEY_ALLOC_QUOTA_OVERRUN, NULL); | 182 | KEY_POS_ALL | KEY_USR_VIEW, |
183 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | ||
180 | if (IS_ERR(keyring)) | 184 | if (IS_ERR(keyring)) |
181 | return PTR_ERR(keyring); | 185 | return PTR_ERR(keyring); |
182 | 186 | ||
183 | spin_lock_irq(&new->tgcred->lock); | 187 | new->process_keyring = keyring; |
184 | if (!new->tgcred->process_keyring) { | 188 | return 0; |
185 | new->tgcred->process_keyring = keyring; | ||
186 | keyring = NULL; | ||
187 | ret = 0; | ||
188 | } else { | ||
189 | ret = -EEXIST; | ||
190 | } | ||
191 | spin_unlock_irq(&new->tgcred->lock); | ||
192 | key_put(keyring); | ||
193 | return ret; | ||
194 | } | 189 | } |
195 | 190 | ||
196 | /* | 191 | /* |
@@ -231,11 +226,12 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
231 | /* create an empty session keyring */ | 226 | /* create an empty session keyring */ |
232 | if (!keyring) { | 227 | if (!keyring) { |
233 | flags = KEY_ALLOC_QUOTA_OVERRUN; | 228 | flags = KEY_ALLOC_QUOTA_OVERRUN; |
234 | if (cred->tgcred->session_keyring) | 229 | if (cred->session_keyring) |
235 | flags = KEY_ALLOC_IN_QUOTA; | 230 | flags = KEY_ALLOC_IN_QUOTA; |
236 | 231 | ||
237 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, | 232 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred, |
238 | cred, flags, NULL); | 233 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, |
234 | flags, NULL); | ||
239 | if (IS_ERR(keyring)) | 235 | if (IS_ERR(keyring)) |
240 | return PTR_ERR(keyring); | 236 | return PTR_ERR(keyring); |
241 | } else { | 237 | } else { |
@@ -243,17 +239,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
243 | } | 239 | } |
244 | 240 | ||
245 | /* install the keyring */ | 241 | /* install the keyring */ |
246 | spin_lock_irq(&cred->tgcred->lock); | 242 | old = cred->session_keyring; |
247 | old = cred->tgcred->session_keyring; | 243 | rcu_assign_pointer(cred->session_keyring, keyring); |
248 | rcu_assign_pointer(cred->tgcred->session_keyring, keyring); | 244 | |
249 | spin_unlock_irq(&cred->tgcred->lock); | 245 | if (old) |
250 | |||
251 | /* we're using RCU on the pointer, but there's no point synchronising | ||
252 | * on it if it didn't previously point to anything */ | ||
253 | if (old) { | ||
254 | synchronize_rcu(); | ||
255 | key_put(old); | 246 | key_put(old); |
256 | } | ||
257 | 247 | ||
258 | return 0; | 248 | return 0; |
259 | } | 249 | } |
@@ -368,9 +358,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
368 | } | 358 | } |
369 | 359 | ||
370 | /* search the process keyring second */ | 360 | /* search the process keyring second */ |
371 | if (cred->tgcred->process_keyring) { | 361 | if (cred->process_keyring) { |
372 | key_ref = keyring_search_aux( | 362 | key_ref = keyring_search_aux( |
373 | make_key_ref(cred->tgcred->process_keyring, 1), | 363 | make_key_ref(cred->process_keyring, 1), |
374 | cred, type, description, match, no_state_check); | 364 | cred, type, description, match, no_state_check); |
375 | if (!IS_ERR(key_ref)) | 365 | if (!IS_ERR(key_ref)) |
376 | goto found; | 366 | goto found; |
@@ -389,12 +379,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
389 | } | 379 | } |
390 | 380 | ||
391 | /* search the session keyring */ | 381 | /* search the session keyring */ |
392 | if (cred->tgcred->session_keyring) { | 382 | if (cred->session_keyring) { |
393 | rcu_read_lock(); | 383 | rcu_read_lock(); |
394 | key_ref = keyring_search_aux( | 384 | key_ref = keyring_search_aux( |
395 | make_key_ref(rcu_dereference( | 385 | make_key_ref(rcu_dereference(cred->session_keyring), 1), |
396 | cred->tgcred->session_keyring), | ||
397 | 1), | ||
398 | cred, type, description, match, no_state_check); | 386 | cred, type, description, match, no_state_check); |
399 | rcu_read_unlock(); | 387 | rcu_read_unlock(); |
400 | 388 | ||
@@ -564,7 +552,7 @@ try_again: | |||
564 | break; | 552 | break; |
565 | 553 | ||
566 | case KEY_SPEC_PROCESS_KEYRING: | 554 | case KEY_SPEC_PROCESS_KEYRING: |
567 | if (!cred->tgcred->process_keyring) { | 555 | if (!cred->process_keyring) { |
568 | if (!(lflags & KEY_LOOKUP_CREATE)) | 556 | if (!(lflags & KEY_LOOKUP_CREATE)) |
569 | goto error; | 557 | goto error; |
570 | 558 | ||
@@ -576,13 +564,13 @@ try_again: | |||
576 | goto reget_creds; | 564 | goto reget_creds; |
577 | } | 565 | } |
578 | 566 | ||
579 | key = cred->tgcred->process_keyring; | 567 | key = cred->process_keyring; |
580 | atomic_inc(&key->usage); | 568 | atomic_inc(&key->usage); |
581 | key_ref = make_key_ref(key, 1); | 569 | key_ref = make_key_ref(key, 1); |
582 | break; | 570 | break; |
583 | 571 | ||
584 | case KEY_SPEC_SESSION_KEYRING: | 572 | case KEY_SPEC_SESSION_KEYRING: |
585 | if (!cred->tgcred->session_keyring) { | 573 | if (!cred->session_keyring) { |
586 | /* always install a session keyring upon access if one | 574 | /* always install a session keyring upon access if one |
587 | * doesn't exist yet */ | 575 | * doesn't exist yet */ |
588 | ret = install_user_keyrings(); | 576 | ret = install_user_keyrings(); |
@@ -597,7 +585,7 @@ try_again: | |||
597 | if (ret < 0) | 585 | if (ret < 0) |
598 | goto error; | 586 | goto error; |
599 | goto reget_creds; | 587 | goto reget_creds; |
600 | } else if (cred->tgcred->session_keyring == | 588 | } else if (cred->session_keyring == |
601 | cred->user->session_keyring && | 589 | cred->user->session_keyring && |
602 | lflags & KEY_LOOKUP_CREATE) { | 590 | lflags & KEY_LOOKUP_CREATE) { |
603 | ret = join_session_keyring(NULL); | 591 | ret = join_session_keyring(NULL); |
@@ -607,7 +595,7 @@ try_again: | |||
607 | } | 595 | } |
608 | 596 | ||
609 | rcu_read_lock(); | 597 | rcu_read_lock(); |
610 | key = rcu_dereference(cred->tgcred->session_keyring); | 598 | key = rcu_dereference(cred->session_keyring); |
611 | atomic_inc(&key->usage); | 599 | atomic_inc(&key->usage); |
612 | rcu_read_unlock(); | 600 | rcu_read_unlock(); |
613 | key_ref = make_key_ref(key, 1); | 601 | key_ref = make_key_ref(key, 1); |
@@ -767,12 +755,6 @@ long join_session_keyring(const char *name) | |||
767 | struct key *keyring; | 755 | struct key *keyring; |
768 | long ret, serial; | 756 | long ret, serial; |
769 | 757 | ||
770 | /* only permit this if there's a single thread in the thread group - | ||
771 | * this avoids us having to adjust the creds on all threads and risking | ||
772 | * ENOMEM */ | ||
773 | if (!current_is_single_threaded()) | ||
774 | return -EMLINK; | ||
775 | |||
776 | new = prepare_creds(); | 758 | new = prepare_creds(); |
777 | if (!new) | 759 | if (!new) |
778 | return -ENOMEM; | 760 | return -ENOMEM; |
@@ -784,7 +766,7 @@ long join_session_keyring(const char *name) | |||
784 | if (ret < 0) | 766 | if (ret < 0) |
785 | goto error; | 767 | goto error; |
786 | 768 | ||
787 | serial = new->tgcred->session_keyring->serial; | 769 | serial = new->session_keyring->serial; |
788 | ret = commit_creds(new); | 770 | ret = commit_creds(new); |
789 | if (ret == 0) | 771 | if (ret == 0) |
790 | ret = serial; | 772 | ret = serial; |
@@ -798,8 +780,10 @@ long join_session_keyring(const char *name) | |||
798 | keyring = find_keyring_by_name(name, false); | 780 | keyring = find_keyring_by_name(name, false); |
799 | if (PTR_ERR(keyring) == -ENOKEY) { | 781 | if (PTR_ERR(keyring) == -ENOKEY) { |
800 | /* not found - try and create a new one */ | 782 | /* not found - try and create a new one */ |
801 | keyring = keyring_alloc(name, old->uid, old->gid, old, | 783 | keyring = keyring_alloc( |
802 | KEY_ALLOC_IN_QUOTA, NULL); | 784 | name, old->uid, old->gid, old, |
785 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, | ||
786 | KEY_ALLOC_IN_QUOTA, NULL); | ||
803 | if (IS_ERR(keyring)) { | 787 | if (IS_ERR(keyring)) { |
804 | ret = PTR_ERR(keyring); | 788 | ret = PTR_ERR(keyring); |
805 | goto error2; | 789 | goto error2; |
@@ -807,6 +791,9 @@ long join_session_keyring(const char *name) | |||
807 | } else if (IS_ERR(keyring)) { | 791 | } else if (IS_ERR(keyring)) { |
808 | ret = PTR_ERR(keyring); | 792 | ret = PTR_ERR(keyring); |
809 | goto error2; | 793 | goto error2; |
794 | } else if (keyring == new->session_keyring) { | ||
795 | ret = 0; | ||
796 | goto error2; | ||
810 | } | 797 | } |
811 | 798 | ||
812 | /* we've got a keyring - now to install it */ | 799 | /* we've got a keyring - now to install it */ |
@@ -863,8 +850,7 @@ void key_change_session_keyring(struct callback_head *twork) | |||
863 | 850 | ||
864 | new->jit_keyring = old->jit_keyring; | 851 | new->jit_keyring = old->jit_keyring; |
865 | new->thread_keyring = key_get(old->thread_keyring); | 852 | new->thread_keyring = key_get(old->thread_keyring); |
866 | new->tgcred->tgid = old->tgcred->tgid; | 853 | new->process_keyring = key_get(old->process_keyring); |
867 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); | ||
868 | 854 | ||
869 | security_transfer_creds(new, old); | 855 | security_transfer_creds(new, old); |
870 | 856 | ||
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 66e21184b559..4bd6bdb74193 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -126,6 +126,7 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
126 | 126 | ||
127 | cred = get_current_cred(); | 127 | cred = get_current_cred(); |
128 | keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, | 128 | keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, |
129 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, | ||
129 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 130 | KEY_ALLOC_QUOTA_OVERRUN, NULL); |
130 | put_cred(cred); | 131 | put_cred(cred); |
131 | if (IS_ERR(keyring)) { | 132 | if (IS_ERR(keyring)) { |
@@ -150,12 +151,12 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
150 | cred->thread_keyring ? cred->thread_keyring->serial : 0); | 151 | cred->thread_keyring ? cred->thread_keyring->serial : 0); |
151 | 152 | ||
152 | prkey = 0; | 153 | prkey = 0; |
153 | if (cred->tgcred->process_keyring) | 154 | if (cred->process_keyring) |
154 | prkey = cred->tgcred->process_keyring->serial; | 155 | prkey = cred->process_keyring->serial; |
155 | sprintf(keyring_str[1], "%d", prkey); | 156 | sprintf(keyring_str[1], "%d", prkey); |
156 | 157 | ||
157 | rcu_read_lock(); | 158 | rcu_read_lock(); |
158 | session = rcu_dereference(cred->tgcred->session_keyring); | 159 | session = rcu_dereference(cred->session_keyring); |
159 | if (!session) | 160 | if (!session) |
160 | session = cred->user->session_keyring; | 161 | session = cred->user->session_keyring; |
161 | sskey = session->serial; | 162 | sskey = session->serial; |
@@ -297,14 +298,14 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) | |||
297 | break; | 298 | break; |
298 | 299 | ||
299 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: | 300 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: |
300 | dest_keyring = key_get(cred->tgcred->process_keyring); | 301 | dest_keyring = key_get(cred->process_keyring); |
301 | if (dest_keyring) | 302 | if (dest_keyring) |
302 | break; | 303 | break; |
303 | 304 | ||
304 | case KEY_REQKEY_DEFL_SESSION_KEYRING: | 305 | case KEY_REQKEY_DEFL_SESSION_KEYRING: |
305 | rcu_read_lock(); | 306 | rcu_read_lock(); |
306 | dest_keyring = key_get( | 307 | dest_keyring = key_get( |
307 | rcu_dereference(cred->tgcred->session_keyring)); | 308 | rcu_dereference(cred->session_keyring)); |
308 | rcu_read_unlock(); | 309 | rcu_read_unlock(); |
309 | 310 | ||
310 | if (dest_keyring) | 311 | if (dest_keyring) |
@@ -347,6 +348,7 @@ static int construct_alloc_key(struct key_type *type, | |||
347 | const struct cred *cred = current_cred(); | 348 | const struct cred *cred = current_cred(); |
348 | unsigned long prealloc; | 349 | unsigned long prealloc; |
349 | struct key *key; | 350 | struct key *key; |
351 | key_perm_t perm; | ||
350 | key_ref_t key_ref; | 352 | key_ref_t key_ref; |
351 | int ret; | 353 | int ret; |
352 | 354 | ||
@@ -355,8 +357,15 @@ static int construct_alloc_key(struct key_type *type, | |||
355 | *_key = NULL; | 357 | *_key = NULL; |
356 | mutex_lock(&user->cons_lock); | 358 | mutex_lock(&user->cons_lock); |
357 | 359 | ||
360 | perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; | ||
361 | perm |= KEY_USR_VIEW; | ||
362 | if (type->read) | ||
363 | perm |= KEY_POS_READ; | ||
364 | if (type == &key_type_keyring || type->update) | ||
365 | perm |= KEY_POS_WRITE; | ||
366 | |||
358 | key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, | 367 | key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, |
359 | KEY_POS_ALL, flags); | 368 | perm, flags); |
360 | if (IS_ERR(key)) | 369 | if (IS_ERR(key)) |
361 | goto alloc_failed; | 370 | goto alloc_failed; |
362 | 371 | ||
diff --git a/security/smack/Kconfig b/security/smack/Kconfig index 603b08784341..e69de9c642b7 100644 --- a/security/smack/Kconfig +++ b/security/smack/Kconfig | |||
@@ -1,6 +1,10 @@ | |||
1 | config SECURITY_SMACK | 1 | config SECURITY_SMACK |
2 | bool "Simplified Mandatory Access Control Kernel Support" | 2 | bool "Simplified Mandatory Access Control Kernel Support" |
3 | depends on NETLABEL && SECURITY_NETWORK | 3 | depends on NET |
4 | depends on INET | ||
5 | depends on SECURITY | ||
6 | select NETLABEL | ||
7 | select SECURITY_NETWORK | ||
4 | default n | 8 | default n |
5 | help | 9 | help |
6 | This selects the Simplified Mandatory Access Control Kernel. | 10 | This selects the Simplified Mandatory Access Control Kernel. |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 99929a50093a..76a5dca46404 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -2063,6 +2063,19 @@ static const struct file_operations smk_revoke_subj_ops = { | |||
2063 | .llseek = generic_file_llseek, | 2063 | .llseek = generic_file_llseek, |
2064 | }; | 2064 | }; |
2065 | 2065 | ||
2066 | static struct kset *smackfs_kset; | ||
2067 | /** | ||
2068 | * smk_init_sysfs - initialize /sys/fs/smackfs | ||
2069 | * | ||
2070 | */ | ||
2071 | static int smk_init_sysfs(void) | ||
2072 | { | ||
2073 | smackfs_kset = kset_create_and_add("smackfs", NULL, fs_kobj); | ||
2074 | if (!smackfs_kset) | ||
2075 | return -ENOMEM; | ||
2076 | return 0; | ||
2077 | } | ||
2078 | |||
2066 | /** | 2079 | /** |
2067 | * smk_fill_super - fill the /smackfs superblock | 2080 | * smk_fill_super - fill the /smackfs superblock |
2068 | * @sb: the empty superblock | 2081 | * @sb: the empty superblock |
@@ -2183,6 +2196,10 @@ static int __init init_smk_fs(void) | |||
2183 | if (!security_module_enable(&smack_ops)) | 2196 | if (!security_module_enable(&smack_ops)) |
2184 | return 0; | 2197 | return 0; |
2185 | 2198 | ||
2199 | err = smk_init_sysfs(); | ||
2200 | if (err) | ||
2201 | printk(KERN_ERR "smackfs: sysfs mountpoint problem.\n"); | ||
2202 | |||
2186 | err = register_filesystem(&smk_fs_type); | 2203 | err = register_filesystem(&smk_fs_type); |
2187 | if (!err) { | 2204 | if (!err) { |
2188 | smackfs_mount = kern_mount(&smk_fs_type); | 2205 | smackfs_mount = kern_mount(&smk_fs_type); |
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index b4c29848b49d..2663145d1197 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/ptrace.h> | 17 | #include <linux/ptrace.h> |
18 | #include <linux/prctl.h> | 18 | #include <linux/prctl.h> |
19 | #include <linux/ratelimit.h> | 19 | #include <linux/ratelimit.h> |
20 | #include <linux/workqueue.h> | ||
20 | 21 | ||
21 | #define YAMA_SCOPE_DISABLED 0 | 22 | #define YAMA_SCOPE_DISABLED 0 |
22 | #define YAMA_SCOPE_RELATIONAL 1 | 23 | #define YAMA_SCOPE_RELATIONAL 1 |
@@ -29,12 +30,37 @@ static int ptrace_scope = YAMA_SCOPE_RELATIONAL; | |||
29 | struct ptrace_relation { | 30 | struct ptrace_relation { |
30 | struct task_struct *tracer; | 31 | struct task_struct *tracer; |
31 | struct task_struct *tracee; | 32 | struct task_struct *tracee; |
33 | bool invalid; | ||
32 | struct list_head node; | 34 | struct list_head node; |
35 | struct rcu_head rcu; | ||
33 | }; | 36 | }; |
34 | 37 | ||
35 | static LIST_HEAD(ptracer_relations); | 38 | static LIST_HEAD(ptracer_relations); |
36 | static DEFINE_SPINLOCK(ptracer_relations_lock); | 39 | static DEFINE_SPINLOCK(ptracer_relations_lock); |
37 | 40 | ||
41 | static void yama_relation_cleanup(struct work_struct *work); | ||
42 | static DECLARE_WORK(yama_relation_work, yama_relation_cleanup); | ||
43 | |||
44 | /** | ||
45 | * yama_relation_cleanup - remove invalid entries from the relation list | ||
46 | * | ||
47 | */ | ||
48 | static void yama_relation_cleanup(struct work_struct *work) | ||
49 | { | ||
50 | struct ptrace_relation *relation; | ||
51 | |||
52 | spin_lock(&ptracer_relations_lock); | ||
53 | rcu_read_lock(); | ||
54 | list_for_each_entry_rcu(relation, &ptracer_relations, node) { | ||
55 | if (relation->invalid) { | ||
56 | list_del_rcu(&relation->node); | ||
57 | kfree_rcu(relation, rcu); | ||
58 | } | ||
59 | } | ||
60 | rcu_read_unlock(); | ||
61 | spin_unlock(&ptracer_relations_lock); | ||
62 | } | ||
63 | |||
38 | /** | 64 | /** |
39 | * yama_ptracer_add - add/replace an exception for this tracer/tracee pair | 65 | * yama_ptracer_add - add/replace an exception for this tracer/tracee pair |
40 | * @tracer: the task_struct of the process doing the ptrace | 66 | * @tracer: the task_struct of the process doing the ptrace |
@@ -48,32 +74,34 @@ static DEFINE_SPINLOCK(ptracer_relations_lock); | |||
48 | static int yama_ptracer_add(struct task_struct *tracer, | 74 | static int yama_ptracer_add(struct task_struct *tracer, |
49 | struct task_struct *tracee) | 75 | struct task_struct *tracee) |
50 | { | 76 | { |
51 | int rc = 0; | 77 | struct ptrace_relation *relation, *added; |
52 | struct ptrace_relation *added; | ||
53 | struct ptrace_relation *entry, *relation = NULL; | ||
54 | 78 | ||
55 | added = kmalloc(sizeof(*added), GFP_KERNEL); | 79 | added = kmalloc(sizeof(*added), GFP_KERNEL); |
56 | if (!added) | 80 | if (!added) |
57 | return -ENOMEM; | 81 | return -ENOMEM; |
58 | 82 | ||
59 | spin_lock_bh(&ptracer_relations_lock); | 83 | added->tracee = tracee; |
60 | list_for_each_entry(entry, &ptracer_relations, node) | 84 | added->tracer = tracer; |
61 | if (entry->tracee == tracee) { | 85 | added->invalid = false; |
62 | relation = entry; | 86 | |
63 | break; | 87 | spin_lock(&ptracer_relations_lock); |
88 | rcu_read_lock(); | ||
89 | list_for_each_entry_rcu(relation, &ptracer_relations, node) { | ||
90 | if (relation->invalid) | ||
91 | continue; | ||
92 | if (relation->tracee == tracee) { | ||
93 | list_replace_rcu(&relation->node, &added->node); | ||
94 | kfree_rcu(relation, rcu); | ||
95 | goto out; | ||
64 | } | 96 | } |
65 | if (!relation) { | ||
66 | relation = added; | ||
67 | relation->tracee = tracee; | ||
68 | list_add(&relation->node, &ptracer_relations); | ||
69 | } | 97 | } |
70 | relation->tracer = tracer; | ||
71 | 98 | ||
72 | spin_unlock_bh(&ptracer_relations_lock); | 99 | list_add_rcu(&added->node, &ptracer_relations); |
73 | if (added != relation) | ||
74 | kfree(added); | ||
75 | 100 | ||
76 | return rc; | 101 | out: |
102 | rcu_read_unlock(); | ||
103 | spin_unlock(&ptracer_relations_lock); | ||
104 | return 0; | ||
77 | } | 105 | } |
78 | 106 | ||
79 | /** | 107 | /** |
@@ -84,16 +112,23 @@ static int yama_ptracer_add(struct task_struct *tracer, | |||
84 | static void yama_ptracer_del(struct task_struct *tracer, | 112 | static void yama_ptracer_del(struct task_struct *tracer, |
85 | struct task_struct *tracee) | 113 | struct task_struct *tracee) |
86 | { | 114 | { |
87 | struct ptrace_relation *relation, *safe; | 115 | struct ptrace_relation *relation; |
116 | bool marked = false; | ||
88 | 117 | ||
89 | spin_lock_bh(&ptracer_relations_lock); | 118 | rcu_read_lock(); |
90 | list_for_each_entry_safe(relation, safe, &ptracer_relations, node) | 119 | list_for_each_entry_rcu(relation, &ptracer_relations, node) { |
120 | if (relation->invalid) | ||
121 | continue; | ||
91 | if (relation->tracee == tracee || | 122 | if (relation->tracee == tracee || |
92 | (tracer && relation->tracer == tracer)) { | 123 | (tracer && relation->tracer == tracer)) { |
93 | list_del(&relation->node); | 124 | relation->invalid = true; |
94 | kfree(relation); | 125 | marked = true; |
95 | } | 126 | } |
96 | spin_unlock_bh(&ptracer_relations_lock); | 127 | } |
128 | rcu_read_unlock(); | ||
129 | |||
130 | if (marked) | ||
131 | schedule_work(&yama_relation_work); | ||
97 | } | 132 | } |
98 | 133 | ||
99 | /** | 134 | /** |
@@ -217,21 +252,22 @@ static int ptracer_exception_found(struct task_struct *tracer, | |||
217 | struct task_struct *parent = NULL; | 252 | struct task_struct *parent = NULL; |
218 | bool found = false; | 253 | bool found = false; |
219 | 254 | ||
220 | spin_lock_bh(&ptracer_relations_lock); | ||
221 | rcu_read_lock(); | 255 | rcu_read_lock(); |
222 | if (!thread_group_leader(tracee)) | 256 | if (!thread_group_leader(tracee)) |
223 | tracee = rcu_dereference(tracee->group_leader); | 257 | tracee = rcu_dereference(tracee->group_leader); |
224 | list_for_each_entry(relation, &ptracer_relations, node) | 258 | list_for_each_entry_rcu(relation, &ptracer_relations, node) { |
259 | if (relation->invalid) | ||
260 | continue; | ||
225 | if (relation->tracee == tracee) { | 261 | if (relation->tracee == tracee) { |
226 | parent = relation->tracer; | 262 | parent = relation->tracer; |
227 | found = true; | 263 | found = true; |
228 | break; | 264 | break; |
229 | } | 265 | } |
266 | } | ||
230 | 267 | ||
231 | if (found && (parent == NULL || task_is_descendant(parent, tracer))) | 268 | if (found && (parent == NULL || task_is_descendant(parent, tracer))) |
232 | rc = 1; | 269 | rc = 1; |
233 | rcu_read_unlock(); | 270 | rcu_read_unlock(); |
234 | spin_unlock_bh(&ptracer_relations_lock); | ||
235 | 271 | ||
236 | return rc; | 272 | return rc; |
237 | } | 273 | } |