aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2007-05-06 17:50:20 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:12:57 -0400
commit73243284463a761e04d69d22c7516b2be7de096c (patch)
tree1a823a613568b48d3a4db694aa02ce380643a3dc
parent906e0be197232c219197d058ef5095baa7764cd4 (diff)
Return EPERM not ECHILD on security_task_wait failure
wait* syscalls return -ECHILD even when an individual PID of a live child was requested explicitly, when security_task_wait denies the operation. This means that something like a broken SELinux policy can produce an unexpected failure that looks just like a bug with wait or ptrace or something. This patch makes do_wait return -EACCES (or other appropriate error returned from security_task_wait() instead of -ECHILD if some children were ruled out solely because security_task_wait failed. [jmorris@namei.org: switch error code to EACCES] Signed-off-by: Roland McGrath <roland@redhat.com> Acked-by: Stephen Smalley <sds@tycho.nsa.gov> Cc: Chris Wright <chrisw@sous-sol.org> Cc: James Morris <jmorris@namei.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--kernel/exit.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index b55ed4cc9104..92369240d91d 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1033,6 +1033,8 @@ asmlinkage void sys_exit_group(int error_code)
1033 1033
1034static int eligible_child(pid_t pid, int options, struct task_struct *p) 1034static int eligible_child(pid_t pid, int options, struct task_struct *p)
1035{ 1035{
1036 int err;
1037
1036 if (pid > 0) { 1038 if (pid > 0) {
1037 if (p->pid != pid) 1039 if (p->pid != pid)
1038 return 0; 1040 return 0;
@@ -1066,8 +1068,9 @@ static int eligible_child(pid_t pid, int options, struct task_struct *p)
1066 if (delay_group_leader(p)) 1068 if (delay_group_leader(p))
1067 return 2; 1069 return 2;
1068 1070
1069 if (security_task_wait(p)) 1071 err = security_task_wait(p);
1070 return 0; 1072 if (err)
1073 return err;
1071 1074
1072 return 1; 1075 return 1;
1073} 1076}
@@ -1449,6 +1452,7 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
1449 DECLARE_WAITQUEUE(wait, current); 1452 DECLARE_WAITQUEUE(wait, current);
1450 struct task_struct *tsk; 1453 struct task_struct *tsk;
1451 int flag, retval; 1454 int flag, retval;
1455 int allowed, denied;
1452 1456
1453 add_wait_queue(&current->signal->wait_chldexit,&wait); 1457 add_wait_queue(&current->signal->wait_chldexit,&wait);
1454repeat: 1458repeat:
@@ -1457,6 +1461,7 @@ repeat:
1457 * match our criteria, even if we are not able to reap it yet. 1461 * match our criteria, even if we are not able to reap it yet.
1458 */ 1462 */
1459 flag = 0; 1463 flag = 0;
1464 allowed = denied = 0;
1460 current->state = TASK_INTERRUPTIBLE; 1465 current->state = TASK_INTERRUPTIBLE;
1461 read_lock(&tasklist_lock); 1466 read_lock(&tasklist_lock);
1462 tsk = current; 1467 tsk = current;
@@ -1472,6 +1477,12 @@ repeat:
1472 if (!ret) 1477 if (!ret)
1473 continue; 1478 continue;
1474 1479
1480 if (unlikely(ret < 0)) {
1481 denied = ret;
1482 continue;
1483 }
1484 allowed = 1;
1485
1475 switch (p->state) { 1486 switch (p->state) {
1476 case TASK_TRACED: 1487 case TASK_TRACED:
1477 /* 1488 /*
@@ -1570,6 +1581,8 @@ check_continued:
1570 goto repeat; 1581 goto repeat;
1571 } 1582 }
1572 retval = -ECHILD; 1583 retval = -ECHILD;
1584 if (unlikely(denied) && !allowed)
1585 retval = denied;
1573end: 1586end:
1574 current->state = TASK_RUNNING; 1587 current->state = TASK_RUNNING;
1575 remove_wait_queue(&current->signal->wait_chldexit,&wait); 1588 remove_wait_queue(&current->signal->wait_chldexit,&wait);