[PATCH] subterfugue-ptrace patch #1 (was Re: vfork)

From: Mike Coleman (mkc@kc.net)
Date: Mon Feb 07 2000 - 01:32:26 EST


Linus Torvalds <torvalds@transmeta.com> writes:
> On 24 Dec 1999, Mike Coleman wrote:
> > I didn't see anyone comment, so I will. I'd like to see this change go in for
> > 2.4. Without it, CLONE_PTRACE is not very useful.
>
> If you can show that it works, and that you can strace a vfork() and over
> a clone(), then send me the patch and I'll apply it in a jiffy. I'd like
> to hear that it actually _does_ work in real life, and I'd be even happier
> if I'd see a working "strace" as a result. Ok?

Ok. SUBTERFUGUE, which I just posted an announcment for, demonstrates process
following over vfork and clone. The patch it uses is pretty similar to what
was being discussed here in December, but adds a couple of things. Here is a
description of the patch (from http://subterfugue.org/patches.html). The
patch itself, against 2.3.42, is appended below.

(Sorry, I don't have a working strace, but I believe the same techniques used
in SUBTERFUGUE will also work for strace. I'll happily render any needed
assistance to make that happen.)

--Mike

------------------------------------------------------------------------------

Here are the changes included in the patch. Most are fairly innocuous
extensions, but the first two might break some things.

  1. The exit_code reported during PTRACE_SYSCALL stops now has its high bit
     (0x80) set, to distinguish it from signal stops. Unfortunately, this
     breaks strace, and probably any other program that uses PTRACE_SYSCALL
     (see ptrace(2)). The fix is pretty simple--just mask off the high bit
     (or adapt the program to make use of the extra information). A patch is
     available that does this for strace. (It doesn't appear that gdb is
     affected.)
  2. When a new child is created with clone and CLONE_PARENT is set, and the
     child is being traced (e.g., it's done a PTRACE_TRACEME), it will now
     report to the first process' parent. This is correct behavior, but it
     opens up what some would consider a security hole--a malicious child
     might unexpectedly invoke PTRACE_TRACEME, causing it to report to a
     waiting parent process that never expected to hear from it. This was
     discussed on linux-kernel for a bit; there didn't seem to be a
     consensus about whether this was even a hole at all.
  3. A new wait flag __WALL is implemented, to allow clone and non-clone
     children to be waited for simultaneously.
  4. A new ptrace command PTRACE_GETPPID is implemented, which lets a
     tracing process discover the original parent of a traced child. This
     information is otherwise unavailable.
  5. Exits of the system calls fork, vfork, and clone are now reported.

------------------------------------------------------------------------------

--- linux-2.3.42/kernel/exit.c.orig Sat Feb 5 02:08:19 2000
+++ linux-2.3.42/kernel/exit.c Sat Feb 5 02:09:32 2000
@@ -445,7 +445,7 @@
         DECLARE_WAITQUEUE(wait, current);
         struct task_struct *p;
 
- if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
+ if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL))
                 return -EINVAL;
 
         add_wait_queue(&current->wait_chldexit,&wait);
@@ -464,8 +464,13 @@
                         if (p->pgrp != -pid)
                                 continue;
                 }
- /* wait for cloned processes iff the __WCLONE flag is set */
- if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+ /* Wait for all children (clone and not) if __WALL is set;
+ * otherwise, wait for clone children *only* if __WCLONE is
+ * set; otherwise, wait for non-clone children *only*. (Note:
+ * A "clone" child here is one that reports to its parent
+ * using a signal other than SIGCHLD.) */
+ if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+ && !(options & __WALL))
                         continue;
                 flag = 1;
                 switch (p->state) {
--- linux-2.3.42/kernel/fork.c.orig Mon Dec 13 17:39:24 1999
+++ linux-2.3.42/kernel/fork.c Sat Feb 5 02:09:32 2000
@@ -646,8 +646,11 @@
         p->run_list.next = NULL;
         p->run_list.prev = NULL;
 
- if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT))
- p->p_pptr = p->p_opptr = current;
+ if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT)) {
+ p->p_opptr = current;
+ if (!(current->flags & PF_PTRACED))
+ p->p_pptr = current;
+ }
         p->p_cptr = NULL;
         init_waitqueue_head(&p->wait_chldexit);
         p->vfork_sem = NULL;
--- linux-2.3.42/include/linux/wait.h.orig Mon Jan 10 20:29:12 2000
+++ linux-2.3.42/include/linux/wait.h Sat Feb 5 02:09:32 2000
@@ -4,6 +4,7 @@
 #define WNOHANG 0x00000001
 #define WUNTRACED 0x00000002
 
+#define __WALL 0x40000000
 #define __WCLONE 0x80000000
 
 #ifdef __KERNEL__
--- linux-2.3.42/include/asm-i386/ptrace.h.orig Tue Dec 9 19:57:09 1997
+++ linux-2.3.42/include/asm-i386/ptrace.h Sat Feb 5 02:09:32 2000
@@ -47,6 +47,8 @@
 #define PTRACE_GETFPREGS 14
 #define PTRACE_SETFPREGS 15
 
+#define PTRACE_GETPPID 20
+
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
 #define instruction_pointer(regs) ((regs)->eip)
--- linux-2.3.42/arch/i386/kernel/entry.S.orig Sat Feb 5 02:07:42 2000
+++ linux-2.3.42/arch/i386/kernel/entry.S Sat Feb 5 02:09:32 2000
@@ -180,6 +180,8 @@
         call SYMBOL_NAME(schedule_tail)
         addl $4, %esp
         GET_CURRENT(%ebx)
+ testb $0x20,flags(%ebx) # PF_TRACESYS
+ jne tracesys_exit # need to set eax first??
         jmp ret_from_sys_call
 
 /*
--- linux-2.3.42/arch/i386/kernel/ptrace.c.orig Sat Feb 5 02:07:22 2000
+++ linux-2.3.42/arch/i386/kernel/ptrace.c Sat Feb 5 02:11:27 2000
@@ -431,6 +431,12 @@
                 break;
         }
 
+ case PTRACE_GETPPID: { /* Who's your daddy? */
+ unsigned long ppid = child->p_opptr->pid;
+ ret = put_user(ppid, (unsigned long *) data);
+ break;
+ }
+
         default:
                 ret = -EIO;
                 break;
@@ -445,7 +451,7 @@
         if ((current->flags & (PF_PTRACED|PF_TRACESYS))
                         != (PF_PTRACED|PF_TRACESYS))
                 return;
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | 0x80;
         current->state = TASK_STOPPED;
         notify_parent(current, SIGCHLD);
         schedule();

-- 
Any sufficiently adverse technology is indistinguishable from Microsoft.

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Mon Feb 07 2000 - 21:00:14 EST