diff options
-rw-r--r-- | include/linux/capability.h | 3 | ||||
-rw-r--r-- | include/linux/init_task.h | 3 | ||||
-rw-r--r-- | include/linux/prctl.h | 9 | ||||
-rw-r--r-- | include/linux/sched.h | 3 | ||||
-rw-r--r-- | include/linux/securebits.h | 25 | ||||
-rw-r--r-- | include/linux/security.h | 16 | ||||
-rw-r--r-- | kernel/sys.c | 27 | ||||
-rw-r--r-- | security/capability.c | 1 | ||||
-rw-r--r-- | security/commoncap.c | 103 | ||||
-rw-r--r-- | security/dummy.c | 2 | ||||
-rw-r--r-- | security/security.c | 4 | ||||
-rw-r--r-- | security/selinux/hooks.c | 5 |
12 files changed, 141 insertions, 60 deletions
diff --git a/include/linux/capability.h b/include/linux/capability.h index 7d50ff6d269f..eaab759b1460 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -155,6 +155,7 @@ typedef struct kernel_cap_struct { | |||
155 | * Add any capability from current's capability bounding set | 155 | * Add any capability from current's capability bounding set |
156 | * to the current process' inheritable set | 156 | * to the current process' inheritable set |
157 | * Allow taking bits out of capability bounding set | 157 | * Allow taking bits out of capability bounding set |
158 | * Allow modification of the securebits for a process | ||
158 | */ | 159 | */ |
159 | 160 | ||
160 | #define CAP_SETPCAP 8 | 161 | #define CAP_SETPCAP 8 |
@@ -490,8 +491,6 @@ extern const kernel_cap_t __cap_init_eff_set; | |||
490 | int capable(int cap); | 491 | int capable(int cap); |
491 | int __capable(struct task_struct *t, int cap); | 492 | int __capable(struct task_struct *t, int cap); |
492 | 493 | ||
493 | extern long cap_prctl_drop(unsigned long cap); | ||
494 | |||
495 | #endif /* __KERNEL__ */ | 494 | #endif /* __KERNEL__ */ |
496 | 495 | ||
497 | #endif /* !_LINUX_CAPABILITY_H */ | 496 | #endif /* !_LINUX_CAPABILITY_H */ |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 37a6f5bc4a92..bf6b8a61f8db 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/ipc.h> | 9 | #include <linux/ipc.h> |
10 | #include <linux/pid_namespace.h> | 10 | #include <linux/pid_namespace.h> |
11 | #include <linux/user_namespace.h> | 11 | #include <linux/user_namespace.h> |
12 | #include <linux/securebits.h> | ||
12 | #include <net/net_namespace.h> | 13 | #include <net/net_namespace.h> |
13 | 14 | ||
14 | #define INIT_FDTABLE \ | 15 | #define INIT_FDTABLE \ |
@@ -172,7 +173,7 @@ extern struct group_info init_groups; | |||
172 | .cap_inheritable = CAP_INIT_INH_SET, \ | 173 | .cap_inheritable = CAP_INIT_INH_SET, \ |
173 | .cap_permitted = CAP_FULL_SET, \ | 174 | .cap_permitted = CAP_FULL_SET, \ |
174 | .cap_bset = CAP_INIT_BSET, \ | 175 | .cap_bset = CAP_INIT_BSET, \ |
175 | .keep_capabilities = 0, \ | 176 | .securebits = SECUREBITS_DEFAULT, \ |
176 | .user = INIT_USER, \ | 177 | .user = INIT_USER, \ |
177 | .comm = "swapper", \ | 178 | .comm = "swapper", \ |
178 | .thread = INIT_THREAD, \ | 179 | .thread = INIT_THREAD, \ |
diff --git a/include/linux/prctl.h b/include/linux/prctl.h index 5c80b1939636..5ad79198d6f9 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h | |||
@@ -16,7 +16,8 @@ | |||
16 | # define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */ | 16 | # define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */ |
17 | # define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */ | 17 | # define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */ |
18 | 18 | ||
19 | /* Get/set whether or not to drop capabilities on setuid() away from uid 0 */ | 19 | /* Get/set whether or not to drop capabilities on setuid() away from |
20 | * uid 0 (as per security/commoncap.c) */ | ||
20 | #define PR_GET_KEEPCAPS 7 | 21 | #define PR_GET_KEEPCAPS 7 |
21 | #define PR_SET_KEEPCAPS 8 | 22 | #define PR_SET_KEEPCAPS 8 |
22 | 23 | ||
@@ -63,7 +64,7 @@ | |||
63 | #define PR_GET_SECCOMP 21 | 64 | #define PR_GET_SECCOMP 21 |
64 | #define PR_SET_SECCOMP 22 | 65 | #define PR_SET_SECCOMP 22 |
65 | 66 | ||
66 | /* Get/set the capability bounding set */ | 67 | /* Get/set the capability bounding set (as per security/commoncap.c) */ |
67 | #define PR_CAPBSET_READ 23 | 68 | #define PR_CAPBSET_READ 23 |
68 | #define PR_CAPBSET_DROP 24 | 69 | #define PR_CAPBSET_DROP 24 |
69 | 70 | ||
@@ -73,4 +74,8 @@ | |||
73 | # define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */ | 74 | # define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */ |
74 | # define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */ | 75 | # define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */ |
75 | 76 | ||
77 | /* Get/set securebits (as per security/commoncap.c) */ | ||
78 | #define PR_GET_SECUREBITS 27 | ||
79 | #define PR_SET_SECUREBITS 28 | ||
80 | |||
76 | #endif /* _LINUX_PRCTL_H */ | 81 | #endif /* _LINUX_PRCTL_H */ |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 9a4f3e63e3bf..024d72b47a0c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -68,7 +68,6 @@ struct sched_param { | |||
68 | #include <linux/smp.h> | 68 | #include <linux/smp.h> |
69 | #include <linux/sem.h> | 69 | #include <linux/sem.h> |
70 | #include <linux/signal.h> | 70 | #include <linux/signal.h> |
71 | #include <linux/securebits.h> | ||
72 | #include <linux/fs_struct.h> | 71 | #include <linux/fs_struct.h> |
73 | #include <linux/compiler.h> | 72 | #include <linux/compiler.h> |
74 | #include <linux/completion.h> | 73 | #include <linux/completion.h> |
@@ -1133,7 +1132,7 @@ struct task_struct { | |||
1133 | gid_t gid,egid,sgid,fsgid; | 1132 | gid_t gid,egid,sgid,fsgid; |
1134 | struct group_info *group_info; | 1133 | struct group_info *group_info; |
1135 | kernel_cap_t cap_effective, cap_inheritable, cap_permitted, cap_bset; | 1134 | kernel_cap_t cap_effective, cap_inheritable, cap_permitted, cap_bset; |
1136 | unsigned keep_capabilities:1; | 1135 | unsigned securebits; |
1137 | struct user_struct *user; | 1136 | struct user_struct *user; |
1138 | #ifdef CONFIG_KEYS | 1137 | #ifdef CONFIG_KEYS |
1139 | struct key *request_key_auth; /* assumed request_key authority */ | 1138 | struct key *request_key_auth; /* assumed request_key authority */ |
diff --git a/include/linux/securebits.h b/include/linux/securebits.h index 5b0617840fa4..c1f19dbceb05 100644 --- a/include/linux/securebits.h +++ b/include/linux/securebits.h | |||
@@ -3,28 +3,39 @@ | |||
3 | 3 | ||
4 | #define SECUREBITS_DEFAULT 0x00000000 | 4 | #define SECUREBITS_DEFAULT 0x00000000 |
5 | 5 | ||
6 | extern unsigned securebits; | ||
7 | |||
8 | /* When set UID 0 has no special privileges. When unset, we support | 6 | /* When set UID 0 has no special privileges. When unset, we support |
9 | inheritance of root-permissions and suid-root executable under | 7 | inheritance of root-permissions and suid-root executable under |
10 | compatibility mode. We raise the effective and inheritable bitmasks | 8 | compatibility mode. We raise the effective and inheritable bitmasks |
11 | *of the executable file* if the effective uid of the new process is | 9 | *of the executable file* if the effective uid of the new process is |
12 | 0. If the real uid is 0, we raise the inheritable bitmask of the | 10 | 0. If the real uid is 0, we raise the inheritable bitmask of the |
13 | executable file. */ | 11 | executable file. */ |
14 | #define SECURE_NOROOT 0 | 12 | #define SECURE_NOROOT 0 |
13 | #define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */ | ||
15 | 14 | ||
16 | /* When set, setuid to/from uid 0 does not trigger capability-"fixes" | 15 | /* When set, setuid to/from uid 0 does not trigger capability-"fixes" |
17 | to be compatible with old programs relying on set*uid to loose | 16 | to be compatible with old programs relying on set*uid to loose |
18 | privileges. When unset, setuid doesn't change privileges. */ | 17 | privileges. When unset, setuid doesn't change privileges. */ |
19 | #define SECURE_NO_SETUID_FIXUP 2 | 18 | #define SECURE_NO_SETUID_FIXUP 2 |
19 | #define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */ | ||
20 | |||
21 | /* When set, a process can retain its capabilities even after | ||
22 | transitioning to a non-root user (the set-uid fixup suppressed by | ||
23 | bit 2). Bit-4 is cleared when a process calls exec(); setting both | ||
24 | bit 4 and 5 will create a barrier through exec that no exec()'d | ||
25 | child can use this feature again. */ | ||
26 | #define SECURE_KEEP_CAPS 4 | ||
27 | #define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */ | ||
20 | 28 | ||
21 | /* Each securesetting is implemented using two bits. One bit specify | 29 | /* Each securesetting is implemented using two bits. One bit specify |
22 | whether the setting is on or off. The other bit specify whether the | 30 | whether the setting is on or off. The other bit specify whether the |
23 | setting is fixed or not. A setting which is fixed cannot be changed | 31 | setting is fixed or not. A setting which is fixed cannot be changed |
24 | from user-level. */ | 32 | from user-level. */ |
33 | #define issecure_mask(X) (1 << (X)) | ||
34 | #define issecure(X) (issecure_mask(X) & current->securebits) | ||
25 | 35 | ||
26 | #define issecure(X) ( (1 << (X+1)) & SECUREBITS_DEFAULT ? \ | 36 | #define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \ |
27 | (1 << (X)) & SECUREBITS_DEFAULT : \ | 37 | issecure_mask(SECURE_NO_SETUID_FIXUP) | \ |
28 | (1 << (X)) & securebits ) | 38 | issecure_mask(SECURE_KEEP_CAPS)) |
39 | #define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1) | ||
29 | 40 | ||
30 | #endif /* !_LINUX_SECUREBITS_H */ | 41 | #endif /* !_LINUX_SECUREBITS_H */ |
diff --git a/include/linux/security.h b/include/linux/security.h index 53a34539382a..e6299e50e210 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -34,8 +34,6 @@ | |||
34 | #include <linux/xfrm.h> | 34 | #include <linux/xfrm.h> |
35 | #include <net/flow.h> | 35 | #include <net/flow.h> |
36 | 36 | ||
37 | extern unsigned securebits; | ||
38 | |||
39 | /* Maximum number of letters for an LSM name string */ | 37 | /* Maximum number of letters for an LSM name string */ |
40 | #define SECURITY_NAME_MAX 10 | 38 | #define SECURITY_NAME_MAX 10 |
41 | 39 | ||
@@ -61,6 +59,8 @@ extern int cap_inode_need_killpriv(struct dentry *dentry); | |||
61 | extern int cap_inode_killpriv(struct dentry *dentry); | 59 | extern int cap_inode_killpriv(struct dentry *dentry); |
62 | extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); | 60 | extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); |
63 | extern void cap_task_reparent_to_init (struct task_struct *p); | 61 | extern void cap_task_reparent_to_init (struct task_struct *p); |
62 | extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | ||
63 | unsigned long arg4, unsigned long arg5, long *rc_p); | ||
64 | extern int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp); | 64 | extern int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp); |
65 | extern int cap_task_setioprio (struct task_struct *p, int ioprio); | 65 | extern int cap_task_setioprio (struct task_struct *p, int ioprio); |
66 | extern int cap_task_setnice (struct task_struct *p, int nice); | 66 | extern int cap_task_setnice (struct task_struct *p, int nice); |
@@ -720,7 +720,9 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
720 | * @arg3 contains a argument. | 720 | * @arg3 contains a argument. |
721 | * @arg4 contains a argument. | 721 | * @arg4 contains a argument. |
722 | * @arg5 contains a argument. | 722 | * @arg5 contains a argument. |
723 | * Return 0 if permission is granted. | 723 | * @rc_p contains a pointer to communicate back the forced return code |
724 | * Return 0 if permission is granted, and non-zero if the security module | ||
725 | * has taken responsibility (setting *rc_p) for the prctl call. | ||
724 | * @task_reparent_to_init: | 726 | * @task_reparent_to_init: |
725 | * Set the security attributes in @p->security for a kernel thread that | 727 | * Set the security attributes in @p->security for a kernel thread that |
726 | * is being reparented to the init task. | 728 | * is being reparented to the init task. |
@@ -1420,7 +1422,7 @@ struct security_operations { | |||
1420 | int (*task_wait) (struct task_struct * p); | 1422 | int (*task_wait) (struct task_struct * p); |
1421 | int (*task_prctl) (int option, unsigned long arg2, | 1423 | int (*task_prctl) (int option, unsigned long arg2, |
1422 | unsigned long arg3, unsigned long arg4, | 1424 | unsigned long arg3, unsigned long arg4, |
1423 | unsigned long arg5); | 1425 | unsigned long arg5, long *rc_p); |
1424 | void (*task_reparent_to_init) (struct task_struct * p); | 1426 | void (*task_reparent_to_init) (struct task_struct * p); |
1425 | void (*task_to_inode)(struct task_struct *p, struct inode *inode); | 1427 | void (*task_to_inode)(struct task_struct *p, struct inode *inode); |
1426 | 1428 | ||
@@ -1684,7 +1686,7 @@ int security_task_kill(struct task_struct *p, struct siginfo *info, | |||
1684 | int sig, u32 secid); | 1686 | int sig, u32 secid); |
1685 | int security_task_wait(struct task_struct *p); | 1687 | int security_task_wait(struct task_struct *p); |
1686 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 1688 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
1687 | unsigned long arg4, unsigned long arg5); | 1689 | unsigned long arg4, unsigned long arg5, long *rc_p); |
1688 | void security_task_reparent_to_init(struct task_struct *p); | 1690 | void security_task_reparent_to_init(struct task_struct *p); |
1689 | void security_task_to_inode(struct task_struct *p, struct inode *inode); | 1691 | void security_task_to_inode(struct task_struct *p, struct inode *inode); |
1690 | int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag); | 1692 | int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag); |
@@ -2271,9 +2273,9 @@ static inline int security_task_wait (struct task_struct *p) | |||
2271 | static inline int security_task_prctl (int option, unsigned long arg2, | 2273 | static inline int security_task_prctl (int option, unsigned long arg2, |
2272 | unsigned long arg3, | 2274 | unsigned long arg3, |
2273 | unsigned long arg4, | 2275 | unsigned long arg4, |
2274 | unsigned long arg5) | 2276 | unsigned long arg5, long *rc_p) |
2275 | { | 2277 | { |
2276 | return 0; | 2278 | return cap_task_prctl(option, arg2, arg3, arg3, arg5, rc_p); |
2277 | } | 2279 | } |
2278 | 2280 | ||
2279 | static inline void security_task_reparent_to_init (struct task_struct *p) | 2281 | static inline void security_task_reparent_to_init (struct task_struct *p) |
diff --git a/kernel/sys.c b/kernel/sys.c index 6a0cc71ee88d..f2a451366953 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1632,10 +1632,9 @@ asmlinkage long sys_umask(int mask) | |||
1632 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | 1632 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, |
1633 | unsigned long arg4, unsigned long arg5) | 1633 | unsigned long arg4, unsigned long arg5) |
1634 | { | 1634 | { |
1635 | long error; | 1635 | long uninitialized_var(error); |
1636 | 1636 | ||
1637 | error = security_task_prctl(option, arg2, arg3, arg4, arg5); | 1637 | if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error)) |
1638 | if (error) | ||
1639 | return error; | 1638 | return error; |
1640 | 1639 | ||
1641 | switch (option) { | 1640 | switch (option) { |
@@ -1688,17 +1687,6 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1688 | error = -EINVAL; | 1687 | error = -EINVAL; |
1689 | break; | 1688 | break; |
1690 | 1689 | ||
1691 | case PR_GET_KEEPCAPS: | ||
1692 | if (current->keep_capabilities) | ||
1693 | error = 1; | ||
1694 | break; | ||
1695 | case PR_SET_KEEPCAPS: | ||
1696 | if (arg2 != 0 && arg2 != 1) { | ||
1697 | error = -EINVAL; | ||
1698 | break; | ||
1699 | } | ||
1700 | current->keep_capabilities = arg2; | ||
1701 | break; | ||
1702 | case PR_SET_NAME: { | 1690 | case PR_SET_NAME: { |
1703 | struct task_struct *me = current; | 1691 | struct task_struct *me = current; |
1704 | unsigned char ncomm[sizeof(me->comm)]; | 1692 | unsigned char ncomm[sizeof(me->comm)]; |
@@ -1732,17 +1720,6 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1732 | case PR_SET_SECCOMP: | 1720 | case PR_SET_SECCOMP: |
1733 | error = prctl_set_seccomp(arg2); | 1721 | error = prctl_set_seccomp(arg2); |
1734 | break; | 1722 | break; |
1735 | |||
1736 | case PR_CAPBSET_READ: | ||
1737 | if (!cap_valid(arg2)) | ||
1738 | return -EINVAL; | ||
1739 | return !!cap_raised(current->cap_bset, arg2); | ||
1740 | case PR_CAPBSET_DROP: | ||
1741 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES | ||
1742 | return cap_prctl_drop(arg2); | ||
1743 | #else | ||
1744 | return -EINVAL; | ||
1745 | #endif | ||
1746 | case PR_GET_TSC: | 1723 | case PR_GET_TSC: |
1747 | error = GET_TSC_CTL(arg2); | 1724 | error = GET_TSC_CTL(arg2); |
1748 | break; | 1725 | break; |
diff --git a/security/capability.c b/security/capability.c index 2c6e06d18fab..38ac54e3aed1 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -44,6 +44,7 @@ static struct security_operations capability_ops = { | |||
44 | .task_setioprio = cap_task_setioprio, | 44 | .task_setioprio = cap_task_setioprio, |
45 | .task_setnice = cap_task_setnice, | 45 | .task_setnice = cap_task_setnice, |
46 | .task_post_setuid = cap_task_post_setuid, | 46 | .task_post_setuid = cap_task_post_setuid, |
47 | .task_prctl = cap_task_prctl, | ||
47 | .task_reparent_to_init = cap_task_reparent_to_init, | 48 | .task_reparent_to_init = cap_task_reparent_to_init, |
48 | 49 | ||
49 | .syslog = cap_syslog, | 50 | .syslog = cap_syslog, |
diff --git a/security/commoncap.c b/security/commoncap.c index 852905789caf..e8c3f5e46705 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -24,11 +24,8 @@ | |||
24 | #include <linux/hugetlb.h> | 24 | #include <linux/hugetlb.h> |
25 | #include <linux/mount.h> | 25 | #include <linux/mount.h> |
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | 27 | #include <linux/prctl.h> | |
28 | /* Global security state */ | 28 | #include <linux/securebits.h> |
29 | |||
30 | unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ | ||
31 | EXPORT_SYMBOL(securebits); | ||
32 | 29 | ||
33 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) | 30 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) |
34 | { | 31 | { |
@@ -368,7 +365,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
368 | 365 | ||
369 | /* AUD: Audit candidate if current->cap_effective is set */ | 366 | /* AUD: Audit candidate if current->cap_effective is set */ |
370 | 367 | ||
371 | current->keep_capabilities = 0; | 368 | current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); |
372 | } | 369 | } |
373 | 370 | ||
374 | int cap_bprm_secureexec (struct linux_binprm *bprm) | 371 | int cap_bprm_secureexec (struct linux_binprm *bprm) |
@@ -448,7 +445,7 @@ static inline void cap_emulate_setxuid (int old_ruid, int old_euid, | |||
448 | { | 445 | { |
449 | if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && | 446 | if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && |
450 | (current->uid != 0 && current->euid != 0 && current->suid != 0) && | 447 | (current->uid != 0 && current->euid != 0 && current->suid != 0) && |
451 | !current->keep_capabilities) { | 448 | !issecure(SECURE_KEEP_CAPS)) { |
452 | cap_clear (current->cap_permitted); | 449 | cap_clear (current->cap_permitted); |
453 | cap_clear (current->cap_effective); | 450 | cap_clear (current->cap_effective); |
454 | } | 451 | } |
@@ -547,7 +544,7 @@ int cap_task_setnice (struct task_struct *p, int nice) | |||
547 | * this task could get inconsistent info. There can be no | 544 | * this task could get inconsistent info. There can be no |
548 | * racing writer bc a task can only change its own caps. | 545 | * racing writer bc a task can only change its own caps. |
549 | */ | 546 | */ |
550 | long cap_prctl_drop(unsigned long cap) | 547 | static long cap_prctl_drop(unsigned long cap) |
551 | { | 548 | { |
552 | if (!capable(CAP_SETPCAP)) | 549 | if (!capable(CAP_SETPCAP)) |
553 | return -EPERM; | 550 | return -EPERM; |
@@ -556,6 +553,7 @@ long cap_prctl_drop(unsigned long cap) | |||
556 | cap_lower(current->cap_bset, cap); | 553 | cap_lower(current->cap_bset, cap); |
557 | return 0; | 554 | return 0; |
558 | } | 555 | } |
556 | |||
559 | #else | 557 | #else |
560 | int cap_task_setscheduler (struct task_struct *p, int policy, | 558 | int cap_task_setscheduler (struct task_struct *p, int policy, |
561 | struct sched_param *lp) | 559 | struct sched_param *lp) |
@@ -572,12 +570,99 @@ int cap_task_setnice (struct task_struct *p, int nice) | |||
572 | } | 570 | } |
573 | #endif | 571 | #endif |
574 | 572 | ||
573 | int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | ||
574 | unsigned long arg4, unsigned long arg5, long *rc_p) | ||
575 | { | ||
576 | long error = 0; | ||
577 | |||
578 | switch (option) { | ||
579 | case PR_CAPBSET_READ: | ||
580 | if (!cap_valid(arg2)) | ||
581 | error = -EINVAL; | ||
582 | else | ||
583 | error = !!cap_raised(current->cap_bset, arg2); | ||
584 | break; | ||
585 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES | ||
586 | case PR_CAPBSET_DROP: | ||
587 | error = cap_prctl_drop(arg2); | ||
588 | break; | ||
589 | |||
590 | /* | ||
591 | * The next four prctl's remain to assist with transitioning a | ||
592 | * system from legacy UID=0 based privilege (when filesystem | ||
593 | * capabilities are not in use) to a system using filesystem | ||
594 | * capabilities only - as the POSIX.1e draft intended. | ||
595 | * | ||
596 | * Note: | ||
597 | * | ||
598 | * PR_SET_SECUREBITS = | ||
599 | * issecure_mask(SECURE_KEEP_CAPS_LOCKED) | ||
600 | * | issecure_mask(SECURE_NOROOT) | ||
601 | * | issecure_mask(SECURE_NOROOT_LOCKED) | ||
602 | * | issecure_mask(SECURE_NO_SETUID_FIXUP) | ||
603 | * | issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED) | ||
604 | * | ||
605 | * will ensure that the current process and all of its | ||
606 | * children will be locked into a pure | ||
607 | * capability-based-privilege environment. | ||
608 | */ | ||
609 | case PR_SET_SECUREBITS: | ||
610 | if ((((current->securebits & SECURE_ALL_LOCKS) >> 1) | ||
611 | & (current->securebits ^ arg2)) /*[1]*/ | ||
612 | || ((current->securebits & SECURE_ALL_LOCKS | ||
613 | & ~arg2)) /*[2]*/ | ||
614 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | ||
615 | || (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/ | ||
616 | /* | ||
617 | * [1] no changing of bits that are locked | ||
618 | * [2] no unlocking of locks | ||
619 | * [3] no setting of unsupported bits | ||
620 | * [4] doing anything requires privilege (go read about | ||
621 | * the "sendmail capabilities bug") | ||
622 | */ | ||
623 | error = -EPERM; /* cannot change a locked bit */ | ||
624 | } else { | ||
625 | current->securebits = arg2; | ||
626 | } | ||
627 | break; | ||
628 | case PR_GET_SECUREBITS: | ||
629 | error = current->securebits; | ||
630 | break; | ||
631 | |||
632 | #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ | ||
633 | |||
634 | case PR_GET_KEEPCAPS: | ||
635 | if (issecure(SECURE_KEEP_CAPS)) | ||
636 | error = 1; | ||
637 | break; | ||
638 | case PR_SET_KEEPCAPS: | ||
639 | if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ | ||
640 | error = -EINVAL; | ||
641 | else if (issecure(SECURE_KEEP_CAPS_LOCKED)) | ||
642 | error = -EPERM; | ||
643 | else if (arg2) | ||
644 | current->securebits |= issecure_mask(SECURE_KEEP_CAPS); | ||
645 | else | ||
646 | current->securebits &= | ||
647 | ~issecure_mask(SECURE_KEEP_CAPS); | ||
648 | break; | ||
649 | |||
650 | default: | ||
651 | /* No functionality available - continue with default */ | ||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | /* Functionality provided */ | ||
656 | *rc_p = error; | ||
657 | return 1; | ||
658 | } | ||
659 | |||
575 | void cap_task_reparent_to_init (struct task_struct *p) | 660 | void cap_task_reparent_to_init (struct task_struct *p) |
576 | { | 661 | { |
577 | cap_set_init_eff(p->cap_effective); | 662 | cap_set_init_eff(p->cap_effective); |
578 | cap_clear(p->cap_inheritable); | 663 | cap_clear(p->cap_inheritable); |
579 | cap_set_full(p->cap_permitted); | 664 | cap_set_full(p->cap_permitted); |
580 | p->keep_capabilities = 0; | 665 | p->securebits = SECUREBITS_DEFAULT; |
581 | return; | 666 | return; |
582 | } | 667 | } |
583 | 668 | ||
diff --git a/security/dummy.c b/security/dummy.c index b0232bbf427b..58d4dd1af5c7 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -604,7 +604,7 @@ static int dummy_task_kill (struct task_struct *p, struct siginfo *info, | |||
604 | } | 604 | } |
605 | 605 | ||
606 | static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3, | 606 | static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3, |
607 | unsigned long arg4, unsigned long arg5) | 607 | unsigned long arg4, unsigned long arg5, long *rc_p) |
608 | { | 608 | { |
609 | return 0; | 609 | return 0; |
610 | } | 610 | } |
diff --git a/security/security.c b/security/security.c index 8a285c7b9962..d5cb5898d967 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -733,9 +733,9 @@ int security_task_wait(struct task_struct *p) | |||
733 | } | 733 | } |
734 | 734 | ||
735 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 735 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
736 | unsigned long arg4, unsigned long arg5) | 736 | unsigned long arg4, unsigned long arg5, long *rc_p) |
737 | { | 737 | { |
738 | return security_ops->task_prctl(option, arg2, arg3, arg4, arg5); | 738 | return security_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p); |
739 | } | 739 | } |
740 | 740 | ||
741 | void security_task_reparent_to_init(struct task_struct *p) | 741 | void security_task_reparent_to_init(struct task_struct *p) |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 308e2cf17d75..04acb5af8317 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3303,12 +3303,13 @@ static int selinux_task_prctl(int option, | |||
3303 | unsigned long arg2, | 3303 | unsigned long arg2, |
3304 | unsigned long arg3, | 3304 | unsigned long arg3, |
3305 | unsigned long arg4, | 3305 | unsigned long arg4, |
3306 | unsigned long arg5) | 3306 | unsigned long arg5, |
3307 | long *rc_p) | ||
3307 | { | 3308 | { |
3308 | /* The current prctl operations do not appear to require | 3309 | /* The current prctl operations do not appear to require |
3309 | any SELinux controls since they merely observe or modify | 3310 | any SELinux controls since they merely observe or modify |
3310 | the state of the current process. */ | 3311 | the state of the current process. */ |
3311 | return 0; | 3312 | return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p); |
3312 | } | 3313 | } |
3313 | 3314 | ||
3314 | static int selinux_task_wait(struct task_struct *p) | 3315 | static int selinux_task_wait(struct task_struct *p) |