diff options
| author | Vitaly Mayatskikh <v.mayatskih@gmail.com> | 2009-09-23 18:56:51 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-24 10:21:00 -0400 |
| commit | dfe16dfa4ac178d9a10b489a73d535c6976e48d2 (patch) | |
| tree | 0ebd7bddf7e99915baed4955faeed2af5bba4203 /kernel | |
| parent | b6e763f07fba6243d2a553ed9a4f3e10a789932a (diff) | |
do_wait: fix sys_waitid()-specific behaviour
do_wait() checks ->wo_info to figure out who is the caller. If it's not
NULL the caller should be sys_waitid(), in that case do_wait() fixes up
the retval or zeros ->wo_info, depending on retval from underlying
function.
This is bug: user can pass ->wo_info == NULL and sys_waitid() will return
incorrect value.
man 2 waitid says:
waitid(): returns 0 on success
Test-case:
int main(void)
{
if (fork())
assert(waitid(P_ALL, 0, NULL, WEXITED) == 0);
return 0;
}
Result:
Assertion `waitid(P_ALL, 0, ((void *)0), 4) == 0' failed.
Move that code to sys_waitid().
User-visible change: sys_waitid() will return 0 on success, either
infop is set or not.
Note, there's another bug in wait_noreap_copyout() which affects
return value of sys_waitid(). It will be fixed in next patch.
Signed-off-by: Vitaly Mayatskikh <v.mayatskih@gmail.com>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/exit.c | 49 |
1 files changed, 23 insertions, 26 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 1daa7f46bccd..2cc69eb8db2a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -1645,32 +1645,6 @@ notask: | |||
| 1645 | end: | 1645 | end: |
| 1646 | __set_current_state(TASK_RUNNING); | 1646 | __set_current_state(TASK_RUNNING); |
| 1647 | remove_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait); | 1647 | remove_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait); |
| 1648 | |||
| 1649 | if (wo->wo_info) { | ||
| 1650 | struct siginfo __user *infop = wo->wo_info; | ||
| 1651 | |||
| 1652 | if (retval > 0) | ||
| 1653 | retval = 0; | ||
| 1654 | else { | ||
| 1655 | /* | ||
| 1656 | * For a WNOHANG return, clear out all the fields | ||
| 1657 | * we would set so the user can easily tell the | ||
| 1658 | * difference. | ||
| 1659 | */ | ||
| 1660 | if (!retval) | ||
| 1661 | retval = put_user(0, &infop->si_signo); | ||
| 1662 | if (!retval) | ||
| 1663 | retval = put_user(0, &infop->si_errno); | ||
| 1664 | if (!retval) | ||
| 1665 | retval = put_user(0, &infop->si_code); | ||
| 1666 | if (!retval) | ||
| 1667 | retval = put_user(0, &infop->si_pid); | ||
| 1668 | if (!retval) | ||
| 1669 | retval = put_user(0, &infop->si_uid); | ||
| 1670 | if (!retval) | ||
| 1671 | retval = put_user(0, &infop->si_status); | ||
| 1672 | } | ||
| 1673 | } | ||
| 1674 | return retval; | 1648 | return retval; |
| 1675 | } | 1649 | } |
| 1676 | 1650 | ||
| @@ -1715,6 +1689,29 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, | |||
| 1715 | wo.wo_stat = NULL; | 1689 | wo.wo_stat = NULL; |
| 1716 | wo.wo_rusage = ru; | 1690 | wo.wo_rusage = ru; |
| 1717 | ret = do_wait(&wo); | 1691 | ret = do_wait(&wo); |
| 1692 | |||
| 1693 | if (ret > 0) { | ||
| 1694 | ret = 0; | ||
| 1695 | } else if (infop) { | ||
| 1696 | /* | ||
| 1697 | * For a WNOHANG return, clear out all the fields | ||
| 1698 | * we would set so the user can easily tell the | ||
| 1699 | * difference. | ||
| 1700 | */ | ||
| 1701 | if (!ret) | ||
| 1702 | ret = put_user(0, &infop->si_signo); | ||
| 1703 | if (!ret) | ||
| 1704 | ret = put_user(0, &infop->si_errno); | ||
| 1705 | if (!ret) | ||
| 1706 | ret = put_user(0, &infop->si_code); | ||
| 1707 | if (!ret) | ||
| 1708 | ret = put_user(0, &infop->si_pid); | ||
| 1709 | if (!ret) | ||
| 1710 | ret = put_user(0, &infop->si_uid); | ||
| 1711 | if (!ret) | ||
| 1712 | ret = put_user(0, &infop->si_status); | ||
| 1713 | } | ||
| 1714 | |||
| 1718 | put_pid(pid); | 1715 | put_pid(pid); |
| 1719 | 1716 | ||
| 1720 | /* avoid REGPARM breakage on x86: */ | 1717 | /* avoid REGPARM breakage on x86: */ |
