diff options
-rw-r--r-- | include/linux/capability.h | 11 | ||||
-rw-r--r-- | include/linux/init_task.h | 13 | ||||
-rw-r--r-- | include/linux/prctl.h | 4 | ||||
-rw-r--r-- | include/linux/sched.h | 2 | ||||
-rw-r--r-- | include/linux/security.h | 5 | ||||
-rw-r--r-- | include/linux/sysctl.h | 3 | ||||
-rw-r--r-- | kernel/fork.c | 1 | ||||
-rw-r--r-- | kernel/sys.c | 13 | ||||
-rw-r--r-- | kernel/sysctl.c | 35 | ||||
-rw-r--r-- | kernel/sysctl_check.c | 7 | ||||
-rw-r--r-- | security/commoncap.c | 44 |
11 files changed, 67 insertions, 71 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h index a1d93da67fe9..ffe7bab8c3a0 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -152,7 +152,9 @@ typedef struct kernel_cap_struct { | |||
152 | * Transfer any capability in your permitted set to any pid, | 152 | * Transfer any capability in your permitted set to any pid, |
153 | * remove any capability in your permitted set from any pid | 153 | * remove any capability in your permitted set from any pid |
154 | * With VFS support for capabilities (neither of above, but) | 154 | * With VFS support for capabilities (neither of above, but) |
155 | * Add any capability to the current process' inheritable set | 155 | * Add any capability from current's capability bounding set |
156 | * to the current process' inheritable set | ||
157 | * Allow taking bits out of capability bounding set | ||
156 | */ | 158 | */ |
157 | 159 | ||
158 | #define CAP_SETPCAP 8 | 160 | #define CAP_SETPCAP 8 |
@@ -202,7 +204,6 @@ typedef struct kernel_cap_struct { | |||
202 | #define CAP_IPC_OWNER 15 | 204 | #define CAP_IPC_OWNER 15 |
203 | 205 | ||
204 | /* Insert and remove kernel modules - modify kernel without limit */ | 206 | /* Insert and remove kernel modules - modify kernel without limit */ |
205 | /* Modify cap_bset */ | ||
206 | #define CAP_SYS_MODULE 16 | 207 | #define CAP_SYS_MODULE 16 |
207 | 208 | ||
208 | /* Allow ioperm/iopl access */ | 209 | /* Allow ioperm/iopl access */ |
@@ -314,6 +315,10 @@ typedef struct kernel_cap_struct { | |||
314 | 315 | ||
315 | #define CAP_SETFCAP 31 | 316 | #define CAP_SETFCAP 31 |
316 | 317 | ||
318 | #define CAP_LAST_CAP CAP_SETFCAP | ||
319 | |||
320 | #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) | ||
321 | |||
317 | /* | 322 | /* |
318 | * Bit location of each capability (used by user-space library and kernel) | 323 | * Bit location of each capability (used by user-space library and kernel) |
319 | */ | 324 | */ |
@@ -465,6 +470,8 @@ extern const kernel_cap_t __cap_init_eff_set; | |||
465 | int capable(int cap); | 470 | int capable(int cap); |
466 | int __capable(struct task_struct *t, int cap); | 471 | int __capable(struct task_struct *t, int cap); |
467 | 472 | ||
473 | extern long cap_prctl_drop(unsigned long cap); | ||
474 | |||
468 | #endif /* __KERNEL__ */ | 475 | #endif /* __KERNEL__ */ |
469 | 476 | ||
470 | #endif /* !_LINUX_CAPABILITY_H */ | 477 | #endif /* !_LINUX_CAPABILITY_H */ |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index f42663eaf655..1f74e1d7415f 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -121,6 +121,18 @@ extern struct group_info init_groups; | |||
121 | #else | 121 | #else |
122 | #define INIT_IDS | 122 | #define INIT_IDS |
123 | #endif | 123 | #endif |
124 | |||
125 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES | ||
126 | /* | ||
127 | * Because of the reduced scope of CAP_SETPCAP when filesystem | ||
128 | * capabilities are in effect, it is safe to allow CAP_SETPCAP to | ||
129 | * be available in the default configuration. | ||
130 | */ | ||
131 | # define CAP_INIT_BSET CAP_FULL_SET | ||
132 | #else | ||
133 | # define CAP_INIT_BSET CAP_INIT_EFF_SET | ||
134 | #endif | ||
135 | |||
124 | /* | 136 | /* |
125 | * INIT_TASK is used to set up the first task table, touch at | 137 | * INIT_TASK is used to set up the first task table, touch at |
126 | * your own risk!. Base=0, limit=0x1fffff (=2MB) | 138 | * your own risk!. Base=0, limit=0x1fffff (=2MB) |
@@ -156,6 +168,7 @@ extern struct group_info init_groups; | |||
156 | .cap_effective = CAP_INIT_EFF_SET, \ | 168 | .cap_effective = CAP_INIT_EFF_SET, \ |
157 | .cap_inheritable = CAP_INIT_INH_SET, \ | 169 | .cap_inheritable = CAP_INIT_INH_SET, \ |
158 | .cap_permitted = CAP_FULL_SET, \ | 170 | .cap_permitted = CAP_FULL_SET, \ |
171 | .cap_bset = CAP_INIT_BSET, \ | ||
159 | .keep_capabilities = 0, \ | 172 | .keep_capabilities = 0, \ |
160 | .user = INIT_USER, \ | 173 | .user = INIT_USER, \ |
161 | .comm = "swapper", \ | 174 | .comm = "swapper", \ |
diff --git a/include/linux/prctl.h b/include/linux/prctl.h index e2eff9079fe9..3800639775ae 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h | |||
@@ -63,4 +63,8 @@ | |||
63 | #define PR_GET_SECCOMP 21 | 63 | #define PR_GET_SECCOMP 21 |
64 | #define PR_SET_SECCOMP 22 | 64 | #define PR_SET_SECCOMP 22 |
65 | 65 | ||
66 | /* Get/set the capability bounding set */ | ||
67 | #define PR_CAPBSET_READ 23 | ||
68 | #define PR_CAPBSET_DROP 24 | ||
69 | |||
66 | #endif /* _LINUX_PRCTL_H */ | 70 | #endif /* _LINUX_PRCTL_H */ |
diff --git a/include/linux/sched.h b/include/linux/sched.h index c30d174a02fa..9c13be3a21e8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1098,7 +1098,7 @@ struct task_struct { | |||
1098 | uid_t uid,euid,suid,fsuid; | 1098 | uid_t uid,euid,suid,fsuid; |
1099 | gid_t gid,egid,sgid,fsgid; | 1099 | gid_t gid,egid,sgid,fsgid; |
1100 | struct group_info *group_info; | 1100 | struct group_info *group_info; |
1101 | kernel_cap_t cap_effective, cap_inheritable, cap_permitted; | 1101 | kernel_cap_t cap_effective, cap_inheritable, cap_permitted, cap_bset; |
1102 | unsigned keep_capabilities:1; | 1102 | unsigned keep_capabilities:1; |
1103 | struct user_struct *user; | 1103 | struct user_struct *user; |
1104 | #ifdef CONFIG_KEYS | 1104 | #ifdef CONFIG_KEYS |
diff --git a/include/linux/security.h b/include/linux/security.h index 9d289e726fd8..fe52cdeab0a6 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -40,11 +40,6 @@ | |||
40 | #define ROOTCONTEXT_MNT 0x04 | 40 | #define ROOTCONTEXT_MNT 0x04 |
41 | #define DEFCONTEXT_MNT 0x08 | 41 | #define DEFCONTEXT_MNT 0x08 |
42 | 42 | ||
43 | /* | ||
44 | * Bounding set | ||
45 | */ | ||
46 | extern kernel_cap_t cap_bset; | ||
47 | |||
48 | extern unsigned securebits; | 43 | extern unsigned securebits; |
49 | 44 | ||
50 | struct ctl_table; | 45 | struct ctl_table; |
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index bf4ae4e138f7..571f01d20a86 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h | |||
@@ -102,7 +102,6 @@ enum | |||
102 | KERN_NODENAME=7, | 102 | KERN_NODENAME=7, |
103 | KERN_DOMAINNAME=8, | 103 | KERN_DOMAINNAME=8, |
104 | 104 | ||
105 | KERN_CAP_BSET=14, /* int: capability bounding set */ | ||
106 | KERN_PANIC=15, /* int: panic timeout */ | 105 | KERN_PANIC=15, /* int: panic timeout */ |
107 | KERN_REALROOTDEV=16, /* real root device to mount after initrd */ | 106 | KERN_REALROOTDEV=16, /* real root device to mount after initrd */ |
108 | 107 | ||
@@ -965,8 +964,6 @@ extern int proc_dostring(struct ctl_table *, int, struct file *, | |||
965 | void __user *, size_t *, loff_t *); | 964 | void __user *, size_t *, loff_t *); |
966 | extern int proc_dointvec(struct ctl_table *, int, struct file *, | 965 | extern int proc_dointvec(struct ctl_table *, int, struct file *, |
967 | void __user *, size_t *, loff_t *); | 966 | void __user *, size_t *, loff_t *); |
968 | extern int proc_dointvec_bset(struct ctl_table *, int, struct file *, | ||
969 | void __user *, size_t *, loff_t *); | ||
970 | extern int proc_dointvec_minmax(struct ctl_table *, int, struct file *, | 967 | extern int proc_dointvec_minmax(struct ctl_table *, int, struct file *, |
971 | void __user *, size_t *, loff_t *); | 968 | void __user *, size_t *, loff_t *); |
972 | extern int proc_dointvec_jiffies(struct ctl_table *, int, struct file *, | 969 | extern int proc_dointvec_jiffies(struct ctl_table *, int, struct file *, |
diff --git a/kernel/fork.c b/kernel/fork.c index 1160f87ba700..2b55b74cd999 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1118,6 +1118,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1118 | #ifdef CONFIG_SECURITY | 1118 | #ifdef CONFIG_SECURITY |
1119 | p->security = NULL; | 1119 | p->security = NULL; |
1120 | #endif | 1120 | #endif |
1121 | p->cap_bset = current->cap_bset; | ||
1121 | p->io_context = NULL; | 1122 | p->io_context = NULL; |
1122 | p->audit_context = NULL; | 1123 | p->audit_context = NULL; |
1123 | cgroup_fork(p); | 1124 | cgroup_fork(p); |
diff --git a/kernel/sys.c b/kernel/sys.c index d1fe71eb4546..4162d12390b6 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1637,7 +1637,7 @@ asmlinkage long sys_umask(int mask) | |||
1637 | mask = xchg(¤t->fs->umask, mask & S_IRWXUGO); | 1637 | mask = xchg(¤t->fs->umask, mask & S_IRWXUGO); |
1638 | return mask; | 1638 | return mask; |
1639 | } | 1639 | } |
1640 | 1640 | ||
1641 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | 1641 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, |
1642 | unsigned long arg4, unsigned long arg5) | 1642 | unsigned long arg4, unsigned long arg5) |
1643 | { | 1643 | { |
@@ -1742,6 +1742,17 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1742 | error = prctl_set_seccomp(arg2); | 1742 | error = prctl_set_seccomp(arg2); |
1743 | break; | 1743 | break; |
1744 | 1744 | ||
1745 | case PR_CAPBSET_READ: | ||
1746 | if (!cap_valid(arg2)) | ||
1747 | return -EINVAL; | ||
1748 | return !!cap_raised(current->cap_bset, arg2); | ||
1749 | case PR_CAPBSET_DROP: | ||
1750 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES | ||
1751 | return cap_prctl_drop(arg2); | ||
1752 | #else | ||
1753 | return -EINVAL; | ||
1754 | #endif | ||
1755 | |||
1745 | default: | 1756 | default: |
1746 | error = -EINVAL; | 1757 | error = -EINVAL; |
1747 | break; | 1758 | break; |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index d0b47b859067..5e2ad5bf88e2 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -419,15 +419,6 @@ static struct ctl_table kern_table[] = { | |||
419 | .proc_handler = &proc_dointvec, | 419 | .proc_handler = &proc_dointvec, |
420 | }, | 420 | }, |
421 | #endif | 421 | #endif |
422 | #ifdef CONFIG_SECURITY_CAPABILITIES | ||
423 | { | ||
424 | .procname = "cap-bound", | ||
425 | .data = &cap_bset, | ||
426 | .maxlen = sizeof(kernel_cap_t), | ||
427 | .mode = 0600, | ||
428 | .proc_handler = &proc_dointvec_bset, | ||
429 | }, | ||
430 | #endif /* def CONFIG_SECURITY_CAPABILITIES */ | ||
431 | #ifdef CONFIG_BLK_DEV_INITRD | 422 | #ifdef CONFIG_BLK_DEV_INITRD |
432 | { | 423 | { |
433 | .ctl_name = KERN_REALROOTDEV, | 424 | .ctl_name = KERN_REALROOTDEV, |
@@ -2096,26 +2087,6 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp, | |||
2096 | return 0; | 2087 | return 0; |
2097 | } | 2088 | } |
2098 | 2089 | ||
2099 | #ifdef CONFIG_SECURITY_CAPABILITIES | ||
2100 | /* | ||
2101 | * init may raise the set. | ||
2102 | */ | ||
2103 | |||
2104 | int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp, | ||
2105 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2106 | { | ||
2107 | int op; | ||
2108 | |||
2109 | if (write && !capable(CAP_SYS_MODULE)) { | ||
2110 | return -EPERM; | ||
2111 | } | ||
2112 | |||
2113 | op = is_global_init(current) ? OP_SET : OP_AND; | ||
2114 | return do_proc_dointvec(table,write,filp,buffer,lenp,ppos, | ||
2115 | do_proc_dointvec_bset_conv,&op); | ||
2116 | } | ||
2117 | #endif /* def CONFIG_SECURITY_CAPABILITIES */ | ||
2118 | |||
2119 | /* | 2090 | /* |
2120 | * Taint values can only be increased | 2091 | * Taint values can only be increased |
2121 | */ | 2092 | */ |
@@ -2529,12 +2500,6 @@ int proc_dointvec(struct ctl_table *table, int write, struct file *filp, | |||
2529 | return -ENOSYS; | 2500 | return -ENOSYS; |
2530 | } | 2501 | } |
2531 | 2502 | ||
2532 | int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp, | ||
2533 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2534 | { | ||
2535 | return -ENOSYS; | ||
2536 | } | ||
2537 | |||
2538 | int proc_dointvec_minmax(struct ctl_table *table, int write, struct file *filp, | 2503 | int proc_dointvec_minmax(struct ctl_table *table, int write, struct file *filp, |
2539 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2504 | void __user *buffer, size_t *lenp, loff_t *ppos) |
2540 | { | 2505 | { |
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c index c3206fa50048..006365b69eaf 100644 --- a/kernel/sysctl_check.c +++ b/kernel/sysctl_check.c | |||
@@ -37,10 +37,6 @@ static struct trans_ctl_table trans_kern_table[] = { | |||
37 | { KERN_NODENAME, "hostname" }, | 37 | { KERN_NODENAME, "hostname" }, |
38 | { KERN_DOMAINNAME, "domainname" }, | 38 | { KERN_DOMAINNAME, "domainname" }, |
39 | 39 | ||
40 | #ifdef CONFIG_SECURITY_CAPABILITIES | ||
41 | { KERN_CAP_BSET, "cap-bound" }, | ||
42 | #endif /* def CONFIG_SECURITY_CAPABILITIES */ | ||
43 | |||
44 | { KERN_PANIC, "panic" }, | 40 | { KERN_PANIC, "panic" }, |
45 | { KERN_REALROOTDEV, "real-root-dev" }, | 41 | { KERN_REALROOTDEV, "real-root-dev" }, |
46 | 42 | ||
@@ -1498,9 +1494,6 @@ int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table) | |||
1498 | (table->strategy == sysctl_ms_jiffies) || | 1494 | (table->strategy == sysctl_ms_jiffies) || |
1499 | (table->proc_handler == proc_dostring) || | 1495 | (table->proc_handler == proc_dostring) || |
1500 | (table->proc_handler == proc_dointvec) || | 1496 | (table->proc_handler == proc_dointvec) || |
1501 | #ifdef CONFIG_SECURITY_CAPABILITIES | ||
1502 | (table->proc_handler == proc_dointvec_bset) || | ||
1503 | #endif /* def CONFIG_SECURITY_CAPABILITIES */ | ||
1504 | (table->proc_handler == proc_dointvec_minmax) || | 1497 | (table->proc_handler == proc_dointvec_minmax) || |
1505 | (table->proc_handler == proc_dointvec_jiffies) || | 1498 | (table->proc_handler == proc_dointvec_jiffies) || |
1506 | (table->proc_handler == proc_dointvec_userhz_jiffies) || | 1499 | (table->proc_handler == proc_dointvec_userhz_jiffies) || |
diff --git a/security/commoncap.c b/security/commoncap.c index 01ab47845dcf..5aba82679a0b 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -25,20 +25,6 @@ | |||
25 | #include <linux/mount.h> | 25 | #include <linux/mount.h> |
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | 27 | ||
28 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES | ||
29 | /* | ||
30 | * Because of the reduced scope of CAP_SETPCAP when filesystem | ||
31 | * capabilities are in effect, it is safe to allow this capability to | ||
32 | * be available in the default configuration. | ||
33 | */ | ||
34 | # define CAP_INIT_BSET CAP_FULL_SET | ||
35 | #else /* ie. ndef CONFIG_SECURITY_FILE_CAPABILITIES */ | ||
36 | # define CAP_INIT_BSET CAP_INIT_EFF_SET | ||
37 | #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ | ||
38 | |||
39 | kernel_cap_t cap_bset = CAP_INIT_BSET; /* systemwide capability bound */ | ||
40 | EXPORT_SYMBOL(cap_bset); | ||
41 | |||
42 | /* Global security state */ | 28 | /* Global security state */ |
43 | 29 | ||
44 | unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ | 30 | unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ |
@@ -140,6 +126,12 @@ int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, | |||
140 | /* incapable of using this inheritable set */ | 126 | /* incapable of using this inheritable set */ |
141 | return -EPERM; | 127 | return -EPERM; |
142 | } | 128 | } |
129 | if (!cap_issubset(*inheritable, | ||
130 | cap_combine(target->cap_inheritable, | ||
131 | current->cap_bset))) { | ||
132 | /* no new pI capabilities outside bounding set */ | ||
133 | return -EPERM; | ||
134 | } | ||
143 | 135 | ||
144 | /* verify restrictions on target's new Permitted set */ | 136 | /* verify restrictions on target's new Permitted set */ |
145 | if (!cap_issubset (*permitted, | 137 | if (!cap_issubset (*permitted, |
@@ -337,10 +329,11 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
337 | /* Derived from fs/exec.c:compute_creds. */ | 329 | /* Derived from fs/exec.c:compute_creds. */ |
338 | kernel_cap_t new_permitted, working; | 330 | kernel_cap_t new_permitted, working; |
339 | 331 | ||
340 | new_permitted = cap_intersect (bprm->cap_permitted, cap_bset); | 332 | new_permitted = cap_intersect(bprm->cap_permitted, |
341 | working = cap_intersect (bprm->cap_inheritable, | 333 | current->cap_bset); |
334 | working = cap_intersect(bprm->cap_inheritable, | ||
342 | current->cap_inheritable); | 335 | current->cap_inheritable); |
343 | new_permitted = cap_combine (new_permitted, working); | 336 | new_permitted = cap_combine(new_permitted, working); |
344 | 337 | ||
345 | if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || | 338 | if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || |
346 | !cap_issubset (new_permitted, current->cap_permitted)) { | 339 | !cap_issubset (new_permitted, current->cap_permitted)) { |
@@ -581,6 +574,23 @@ int cap_task_kill(struct task_struct *p, struct siginfo *info, | |||
581 | 574 | ||
582 | return -EPERM; | 575 | return -EPERM; |
583 | } | 576 | } |
577 | |||
578 | /* | ||
579 | * called from kernel/sys.c for prctl(PR_CABSET_DROP) | ||
580 | * done without task_capability_lock() because it introduces | ||
581 | * no new races - i.e. only another task doing capget() on | ||
582 | * this task could get inconsistent info. There can be no | ||
583 | * racing writer bc a task can only change its own caps. | ||
584 | */ | ||
585 | long cap_prctl_drop(unsigned long cap) | ||
586 | { | ||
587 | if (!capable(CAP_SETPCAP)) | ||
588 | return -EPERM; | ||
589 | if (!cap_valid(cap)) | ||
590 | return -EINVAL; | ||
591 | cap_lower(current->cap_bset, cap); | ||
592 | return 0; | ||
593 | } | ||
584 | #else | 594 | #else |
585 | int cap_task_setscheduler (struct task_struct *p, int policy, | 595 | int cap_task_setscheduler (struct task_struct *p, int policy, |
586 | struct sched_param *lp) | 596 | struct sched_param *lp) |