Roland said: Vanilla 2.6.9 is not affected, but RHEL4 probably is. It has backported the relevant changes from the later upstream code so it probably behaves like the vanilla upstream kernel does now. RHEL5 is probably not affected. It has the ptrace subsystem replaced such that I think this code path no longer involved in the cases that can trigger the problem.
Roland wrote: ....The original "if (p->state > TASK_STOPPED)" line predated the introduction of TASK_TRACED. When written, it was a correct test for what we now write as "if (p->exit_state)". The patch below is the minimal necessary change to restore the original sense of the test intended and correct the pathological behavior of this test case. This seems like the right thing to put in right away. (I tested it with the case you forwarded.) That covers the "security" problem, such as it is. (It doesn't seem really exploitable to me, since if you kill all the traced processes it still dies, no permanent leaks or anything.) Later we can get into what the check is there for at all and clean that up right..... --- [PATCH] wait_task_stopped: Check p->exit_state instead of TASK_TRACED The original meaning of the old test (p->state > TASK_STOPPED) was "not dead", since it was before TASK_TRACED existed and before the state/exit_state split. It was a wrong correction in commit 14bf01bb0599c89fc7f426d20353b76e12555308 to make this test for TASK_TRACED instead. It should have been changed when TASK_TRACED was introducted and again when exit_state was introduced. Signed-off-by: Roland McGrath <roland> --- kernel/exit.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/kernel/exit.c b/kernel/exit.c index f1aec27..cd0f1d4 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1386,8 +1386,7 @@ static int wait_task_stopped(struct task_struct *p, int delayed_group_leader, int why = (p->ptrace & PT_PTRACED) ? CLD_TRAPPED : CLD_STOPPED; exit_code = p->exit_code; - if (unlikely(!exit_code) || - unlikely(p->state & TASK_TRACED)) + if (unlikely(!exit_code) || unlikely(p->exit_state)) goto bail_ref; return wait_noreap_copyout(p, pid, uid, why, (exit_code << 8) | 0x7f,
Adding this issue desription comment: Scott James Remnant of Ubuntu reported a bug that could allow a local, unprivileged user to cause a kernel hang. "The spin occurs inside sys_waitid (1696..1729) when called with the WNOWAIT option and a signal from a ptraced process to be waited upon; the syscall never exits, so depending on the kernel state, the effect can be anything from a process spinning to a full system hang."