• R/O
  • HTTP
  • SSH
  • HTTPS

linux-2.4.36: Commit

2.4.36-stable kernel tree


Commit MetaInfo

Revisionbdcb9a96032e26339dbf4aeb26ac8e81541fc7db (tree)
Time2007-12-17 08:06:51
AuthorWilly Tarreau <w@1wt....>
CommiterWilly Tarreau

Log Message

[PATCH] prevent SIGCONT from waking up a PTRACED process (CVE-2007-4774)

Tavis Ormandy discovered that it was possible to bypass systrace policies
by flooding the ptraced process with SIGCONT signals. The same is possible
with SIGKILL, but obviously the attacker has to finely adjust its target
as it can only shoot once.

This issue was assigned identifier CVE-2007-4774.

The following patch fixes the SIGCONT case and adds some documentation for
authors of monitoring programs such as systrace.

Signed-off-by: Willy Tarreau <w@1wt.eu>
Acked-by: Tavis Ormandy <taviso@sdf.lonestar.org>

Change Summary

Incremental Difference

--- /dev/null
+++ b/Documentation/ptrace.txt
@@ -0,0 +1,50 @@
1+
2+ -=* Known limitations of ptace-based security policy enforcement *=-
3+
4+Some programs such as Systrace[1] can make use of the ptrace mechanisms to
5+control the parameters of every syscall used by a given process.
6+
7+This is possible due to the call to syscall_trace() just a few instructions
8+before calling the syscall's function. syscall_trace() sets the traced task's
9+state to TASK_STOPPED, makes it sleep and wakes the parent which will be able
10+to analyze the call through ptrace().
11+
12+Now that the traced task is sleeping, what happens if it receives a signal ?
13+Tavis Ormandy discovered that up to and including 2.4.35.4, if a traced task
14+in a TASK_STOPPED state receives either a SIGCONT or SIGKILL signal, it resumes
15+its execution and completes its syscall without the parent being able to act in
16+any way.
17+
18+With SIGCONT, execution resumes normally, and confuses the parent which sees
19+a running task where it would expect a stopped one. With SIGKILL, the task
20+is really killed right after the syscall completion.
21+
22+In both cases, if the parent was responsible for checking the syscall
23+parameters, its control can be bypassed using this trick. While the situation
24+is easily fixable in the case of the SIGCONT signal (and will be fixed in
25+version 2.4.36), it looks like it will not be fixed without a massive change
26+in the way ptrace works on all architectures, which is clearly not an option
27+at this stage of the stable 2.4 branch.
28+
29+It was demonstrated that although extremely difficult because of timing race
30+and also because only one attempt is permitted, forking processes, creating
31+files or directories, and other single-syscall actions may escape from the
32+control of the parent. In all situations, the parent will notice that the
33+traced process is running again and/or has a wrong syscall number.
34+
35+It is recommended that programs designed to monitor and/or control other
36+process activities using ptrace report alerts when the monitored process
37+gets suddenly killed or unexpectedly wakes up while its syscall parameters
38+are being checked.
39+
40+
41+References :
42+------------
43+[1] http://www.systrace.org/
44+
45+Status of this document :
46+-------------------------
47+Revision : 1.0
48+Created : 2007/12/09 - Willy Tarreau
49+Updated : 2007/12/09
50+
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -409,8 +409,19 @@ static int ignored_signal(int sig, struct task_struct *t)
409409 static void handle_stop_signal(int sig, struct task_struct *t)
410410 {
411411 switch (sig) {
412- case SIGKILL: case SIGCONT:
413- /* Wake up the process if stopped. */
412+ case SIGCONT:
413+ /* SIGCONT must not wake a task while it's being traced */
414+ if ((t->state == TASK_STOPPED) &&
415+ ((t->ptrace & (PT_PTRACED|PT_TRACESYS)) ==
416+ (PT_PTRACED|PT_TRACESYS)))
417+ return;
418+ /* fall through */
419+ case SIGKILL:
420+ /* Wake up the process if stopped.
421+ * Note that if the process is being traced, waking it up
422+ * will make it continue before being killed. This may end
423+ * up unexpectedly completing whatever syscall is pending.
424+ */
414425 if (t->state == TASK_STOPPED)
415426 wake_up_process(t);
416427 t->exit_code = 0;
Show on old repository browser