diff options
author | Serge Hallyn <serge@hallyn.com> | 2008-02-29 10:14:57 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-03-20 12:46:36 -0400 |
commit | aedb60a67c10a0861af179725d060765262ba0fb (patch) | |
tree | 4a4a316f9f7d1ab0bf4da2cdd5c802bfb05c947f | |
parent | 457fb605834504af294916411be128a9b21fc3f6 (diff) |
file capabilities: remove cap_task_kill()
The original justification for cap_task_kill() was as follows:
check_kill_permission() does appropriate uid equivalence checks.
However with file capabilities it becomes possible for an
unprivileged user to execute a file with file capabilities
resulting in a more privileged task with the same uid.
However now that cap_task_kill() always returns 0 (permission
granted) when p->uid==current->uid, the whole hook is worthless,
and only likely to create more subtle problems in the corner cases
where it might still be called but return -EPERM. Those cases
are basically when uids are different but euid/suid is equivalent
as per the check in check_kill_permission().
One example of a still-broken application is 'at' for non-root users.
This patch removes cap_task_kill().
Signed-off-by: Serge Hallyn <serge@hallyn.com>
Acked-by: Andrew G. Morgan <morgan@kernel.org>
Earlier-version-tested-by: Luiz Fernando N. Capitulino <lcapitulino@mandriva.com.br>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/security.h | 3 | ||||
-rw-r--r-- | security/capability.c | 1 | ||||
-rw-r--r-- | security/commoncap.c | 40 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 5 |
4 files changed, 1 insertions, 48 deletions
diff --git a/include/linux/security.h b/include/linux/security.h index b07357ca2137..c673dfd4dffc 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -57,7 +57,6 @@ extern int cap_inode_need_killpriv(struct dentry *dentry); | |||
57 | extern int cap_inode_killpriv(struct dentry *dentry); | 57 | extern int cap_inode_killpriv(struct dentry *dentry); |
58 | extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); | 58 | extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); |
59 | extern void cap_task_reparent_to_init (struct task_struct *p); | 59 | extern void cap_task_reparent_to_init (struct task_struct *p); |
60 | extern int cap_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid); | ||
61 | extern int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp); | 60 | extern int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp); |
62 | extern int cap_task_setioprio (struct task_struct *p, int ioprio); | 61 | extern int cap_task_setioprio (struct task_struct *p, int ioprio); |
63 | extern int cap_task_setnice (struct task_struct *p, int nice); | 62 | extern int cap_task_setnice (struct task_struct *p, int nice); |
@@ -2187,7 +2186,7 @@ static inline int security_task_kill (struct task_struct *p, | |||
2187 | struct siginfo *info, int sig, | 2186 | struct siginfo *info, int sig, |
2188 | u32 secid) | 2187 | u32 secid) |
2189 | { | 2188 | { |
2190 | return cap_task_kill(p, info, sig, secid); | 2189 | return 0; |
2191 | } | 2190 | } |
2192 | 2191 | ||
2193 | static inline int security_task_wait (struct task_struct *p) | 2192 | static inline int security_task_wait (struct task_struct *p) |
diff --git a/security/capability.c b/security/capability.c index 9e99f36a8b5c..2c6e06d18fab 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -40,7 +40,6 @@ static struct security_operations capability_ops = { | |||
40 | .inode_need_killpriv = cap_inode_need_killpriv, | 40 | .inode_need_killpriv = cap_inode_need_killpriv, |
41 | .inode_killpriv = cap_inode_killpriv, | 41 | .inode_killpriv = cap_inode_killpriv, |
42 | 42 | ||
43 | .task_kill = cap_task_kill, | ||
44 | .task_setscheduler = cap_task_setscheduler, | 43 | .task_setscheduler = cap_task_setscheduler, |
45 | .task_setioprio = cap_task_setioprio, | 44 | .task_setioprio = cap_task_setioprio, |
46 | .task_setnice = cap_task_setnice, | 45 | .task_setnice = cap_task_setnice, |
diff --git a/security/commoncap.c b/security/commoncap.c index bb0c095f5761..06d5c9469ba3 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -540,41 +540,6 @@ int cap_task_setnice (struct task_struct *p, int nice) | |||
540 | return cap_safe_nice(p); | 540 | return cap_safe_nice(p); |
541 | } | 541 | } |
542 | 542 | ||
543 | int cap_task_kill(struct task_struct *p, struct siginfo *info, | ||
544 | int sig, u32 secid) | ||
545 | { | ||
546 | if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info))) | ||
547 | return 0; | ||
548 | |||
549 | /* | ||
550 | * Running a setuid root program raises your capabilities. | ||
551 | * Killing your own setuid root processes was previously | ||
552 | * allowed. | ||
553 | * We must preserve legacy signal behavior in this case. | ||
554 | */ | ||
555 | if (p->uid == current->uid) | ||
556 | return 0; | ||
557 | |||
558 | /* sigcont is permitted within same session */ | ||
559 | if (sig == SIGCONT && (task_session_nr(current) == task_session_nr(p))) | ||
560 | return 0; | ||
561 | |||
562 | if (secid) | ||
563 | /* | ||
564 | * Signal sent as a particular user. | ||
565 | * Capabilities are ignored. May be wrong, but it's the | ||
566 | * only thing we can do at the moment. | ||
567 | * Used only by usb drivers? | ||
568 | */ | ||
569 | return 0; | ||
570 | if (cap_issubset(p->cap_permitted, current->cap_permitted)) | ||
571 | return 0; | ||
572 | if (capable(CAP_KILL)) | ||
573 | return 0; | ||
574 | |||
575 | return -EPERM; | ||
576 | } | ||
577 | |||
578 | /* | 543 | /* |
579 | * called from kernel/sys.c for prctl(PR_CABSET_DROP) | 544 | * called from kernel/sys.c for prctl(PR_CABSET_DROP) |
580 | * done without task_capability_lock() because it introduces | 545 | * done without task_capability_lock() because it introduces |
@@ -605,11 +570,6 @@ int cap_task_setnice (struct task_struct *p, int nice) | |||
605 | { | 570 | { |
606 | return 0; | 571 | return 0; |
607 | } | 572 | } |
608 | int cap_task_kill(struct task_struct *p, struct siginfo *info, | ||
609 | int sig, u32 secid) | ||
610 | { | ||
611 | return 0; | ||
612 | } | ||
613 | #endif | 573 | #endif |
614 | 574 | ||
615 | void cap_task_reparent_to_init (struct task_struct *p) | 575 | void cap_task_reparent_to_init (struct task_struct *p) |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 38d707593b31..732ba27923c4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -1117,11 +1117,6 @@ static int smack_task_movememory(struct task_struct *p) | |||
1117 | static int smack_task_kill(struct task_struct *p, struct siginfo *info, | 1117 | static int smack_task_kill(struct task_struct *p, struct siginfo *info, |
1118 | int sig, u32 secid) | 1118 | int sig, u32 secid) |
1119 | { | 1119 | { |
1120 | int rc; | ||
1121 | |||
1122 | rc = cap_task_kill(p, info, sig, secid); | ||
1123 | if (rc != 0) | ||
1124 | return rc; | ||
1125 | /* | 1120 | /* |
1126 | * Special cases where signals really ought to go through | 1121 | * Special cases where signals really ought to go through |
1127 | * in spite of policy. Stephen Smalley suggests it may | 1122 | * in spite of policy. Stephen Smalley suggests it may |