2002-10-27 18:44:07

by Daniel Jacobowitz

[permalink] [raw]
Subject: PATCH: ptrace support for fork/vfork/clone events [1/3]

I've submitted this a couple of times and gotten no feedback, but I'm a
sucker for pain, so here it is again - I'd really like to see this patch in
2.6.

Why? Without it, there are some things GDB can't do. You can't step over a
call to fork(), because when you do, the child process will hit the
parent's step breakpoint and exit with SIGTRAP. You also can't choose to
debug the child instead of the parent, because GDB doesn't have a chance to
attach to it.

The code is in three parts:
1. Factor out some common ptrace code; implement PTRACE_O_TRACESYSGOOD
and PTRACE_SETOPTIONS for every architecture. This one will let me unify
a great deal more of the architecture ptrace implementations later.
2. Add a new clone flag, CLONE_UNTRACED, and force it in all kernel_thread
implementations. Needed by the next patch. This one touches every
architecture and some of them in assembly; I've tried to get them all
correct.
3. Add PTRACE_GETEVENTMSG and four new flags to PTRACE_SETOPTIONS, to allow
tracing fork, vfork, clone, and exec events.

The patches have been tested on i386, and a 2.4 backport tested on SH, MIPS,
i386, PowerPC, and ARM; I have GDB using this mechanism and have run that
through more stress tests than I really want to remember on the weekend.

The three patches are available at:
http://crack.them.org/~drow/forks/

or from the BK tree at:
bk://nevyn.them.org:5000

Here's the first one.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.808 -> 1.809
# include/asm-i386/ptrace.h 1.2.1.1 -> 1.4
# arch/s390x/kernel/ptrace.c 1.7.1.1 -> 1.9
# include/linux/ptrace.h 1.3 -> 1.4
# arch/arm/kernel/ptrace.c 1.12.1.2 -> 1.14
# arch/sh/kernel/ptrace.c 1.7 -> 1.8
# arch/parisc/kernel/ptrace.c 1.4 -> 1.5
# include/asm-s390x/ptrace.h 1.3.1.1 -> 1.5
# arch/mips64/kernel/ptrace.c 1.6 -> 1.7
# arch/ppc/kernel/ptrace.c 1.10 -> 1.11
# arch/i386/kernel/ptrace.c 1.13 -> 1.14
# arch/x86_64/ia32/ptrace32.c 1.2.1.1 -> 1.4
# arch/ppc64/kernel/ptrace.c 1.3.1.1 -> 1.5
# arch/m68k/kernel/ptrace.c 1.7 -> 1.8
# include/asm-x86_64/ptrace.h 1.3.1.1 -> 1.5
# arch/x86_64/kernel/ptrace.c 1.3.1.1 -> 1.5
# arch/cris/kernel/ptrace.c 1.8 -> 1.9
# arch/ppc64/kernel/ptrace32.c 1.5.1.1 -> 1.7
# include/asm-arm/ptrace.h 1.2 -> 1.3
# include/asm-mips/ptrace.h 1.2 -> 1.3
# arch/ia64/ia32/sys_ia32.c 1.23 -> 1.24
# include/asm-ia64/ptrace.h 1.4 -> 1.5
# include/asm-s390/ptrace.h 1.5.1.1 -> 1.7
# include/asm-sh/ptrace.h 1.2 -> 1.3
# arch/alpha/kernel/ptrace.c 1.9 -> 1.10
# arch/s390/kernel/ptrace.c 1.8.1.1 -> 1.10
# include/asm-mips64/ptrace.h 1.1 -> 1.2
# arch/sparc64/kernel/ptrace.c 1.16 -> 1.17
# arch/ia64/kernel/ptrace.c 1.11.1.1 -> 1.13
# arch/sparc/kernel/ptrace.c 1.11 -> 1.12
# arch/mips/kernel/ptrace.c 1.8 -> 1.9
# kernel/ptrace.c 1.18 -> 1.19
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/26 [email protected] 1.809
# Merge kernel.org changes
# --------------------------------------------
#
diff -Nru a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
--- a/arch/alpha/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/alpha/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -383,7 +383,7 @@
goto out;

default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
goto out;
}
out:
@@ -400,7 +400,8 @@
return;
if (!(current->ptrace & PT_PTRACED))
return;
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0);
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
diff -Nru a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
--- a/arch/arm/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/arm/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -692,16 +692,8 @@
ret = ptrace_setfpregs(child, (void *)data);
break;

- case PTRACE_SETOPTIONS:
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- ret = 0;
- break;
-
default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}

diff -Nru a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c
--- a/arch/cris/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/cris/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -292,7 +292,7 @@
}

default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}
out_tsk:
@@ -307,10 +307,8 @@
if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) !=
(PT_PTRACED | PT_TRACESYS))
return;
- /* TODO: make a way to distinguish between a syscall stop and SIGTRAP
- * delivery like in the i386 port ?
- */
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0);
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
diff -Nru a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
--- a/arch/i386/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/i386/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -425,17 +425,8 @@
break;
}

- case PTRACE_SETOPTIONS: {
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- ret = 0;
- break;
- }
-
default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}
out_tsk:
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c Sat Oct 26 20:09:49 2002
+++ b/arch/ia64/ia32/sys_ia32.c Sat Oct 26 20:09:49 2002
@@ -3090,7 +3090,7 @@
break;

default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;

}
diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
--- a/arch/ia64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/ia64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -1268,16 +1268,8 @@
ret = ptrace_setregs(child, (struct pt_all_user_regs*) data);
goto out_tsk;

- case PTRACE_SETOPTIONS:
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- ret = 0;
- break;
-
default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
goto out_tsk;
}
out_tsk:
diff -Nru a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
--- a/arch/m68k/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/m68k/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -355,7 +355,7 @@
}

default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}
out_tsk:
@@ -370,7 +370,8 @@
if (!current->thread.work.delayed_trace &&
!current->thread.work.syscall_trace)
return;
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0);
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
diff -Nru a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
--- a/arch/mips/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/mips/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -304,16 +304,8 @@
res = ptrace_detach(child, data);
break;

- case PTRACE_SETOPTIONS:
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- res = 0;
- break;
-
default:
- res = -EIO;
+ res = ptrace_request(child, request, addr, data);
goto out;
}
out_tsk:
diff -Nru a/arch/mips64/kernel/ptrace.c b/arch/mips64/kernel/ptrace.c
--- a/arch/mips64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/mips64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -275,17 +275,8 @@
ret = ptrace_detach(child, data);
break;

- case PTRACE_SETOPTIONS: {
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- ret = 0;
- break;
- }
-
default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}

@@ -535,17 +526,8 @@
ret = ptrace_detach(child, data);
break;

- case PTRACE_SETOPTIONS: {
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- ret = 0;
- break;
- }
-
default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}

diff -Nru a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
--- a/arch/parisc/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/parisc/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -244,7 +244,7 @@
goto out_tsk;

default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
goto out_tsk;
}

@@ -269,7 +269,8 @@
if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
(PT_PTRACED|PT_TRACESYS))
return;
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0);
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
diff -Nru a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
--- a/arch/ppc/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/ppc/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -339,7 +339,7 @@
#endif

default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}
out_tsk:
@@ -354,7 +354,8 @@
if (!test_thread_flag(TIF_SYSCALL_TRACE)
|| !(current->ptrace & PT_PTRACED))
return;
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0);
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
diff -Nru a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c
--- a/arch/ppc64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/ppc64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -276,7 +276,7 @@
}

default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}
out_tsk:
@@ -292,7 +292,8 @@
return;
if (!(current->ptrace & PT_PTRACED))
return;
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0);
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
diff -Nru a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c
--- a/arch/ppc64/kernel/ptrace32.c Sat Oct 26 20:09:49 2002
+++ b/arch/ppc64/kernel/ptrace32.c Sat Oct 26 20:09:49 2002
@@ -413,7 +413,7 @@


default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}
out_tsk:
diff -Nru a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
--- a/arch/s390/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/s390/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -307,15 +307,8 @@
copied += sizeof(unsigned long);
}
return 0;
-
- case PTRACE_SETOPTIONS:
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- return 0;
}
- return -EIO;
+ return ptrace_request(child, request, addr, data);
}

asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
diff -Nru a/arch/s390x/kernel/ptrace.c b/arch/s390x/kernel/ptrace.c
--- a/arch/s390x/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/s390x/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -261,7 +261,7 @@
}
return 0;
}
- return -EIO;
+ return ptrace_request(child, request, addr, data);
}

#ifdef CONFIG_S390_SUPPORT
@@ -469,7 +469,7 @@
}
return 0;
}
- return -EIO;
+ return ptrace_request(child, request, addr, data);
}
#endif

@@ -538,12 +538,6 @@
/* detach a process that was attached. */
return ptrace_detach(child, data);

- case PTRACE_SETOPTIONS:
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- return 0;
/* Do requests that differ for 31/64 bit */
default:
#ifdef CONFIG_S390_SUPPORT
@@ -551,8 +545,8 @@
return do_ptrace_emu31(child, request, addr, data);
#endif
return do_ptrace_normal(child, request, addr, data);
-
}
+ /* Not reached. */
return -EIO;
}

diff -Nru a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
--- a/arch/sh/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/sh/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -356,17 +356,8 @@
ret = ptrace_detach(child, data);
break;

- case PTRACE_SETOPTIONS: {
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- ret = 0;
- break;
- }
-
default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}
out_tsk:
diff -Nru a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
--- a/arch/sparc/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/sparc/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -584,10 +584,15 @@

/* PTRACE_DUMPCORE unsupported... */

- default:
- pt_error_return(regs, EIO);
+ default: {
+ int err = ptrace_request(child, request, addr, data);
+ if (err)
+ pt_error_return(regs, -err);
+ else
+ pt_succ_return(regs, 0);
goto out_tsk;
}
+ }
out_tsk:
if (child)
put_task_struct(child);
@@ -604,7 +609,8 @@
return;
if (!(current->ptrace & PT_PTRACED))
return;
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0);
current->state = TASK_STOPPED;
current->thread.flags ^= MAGIC_CONSTANT;
notify_parent(current, SIGCHLD);
diff -Nru a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
--- a/arch/sparc64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/sparc64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -571,10 +571,15 @@

/* PTRACE_DUMPCORE unsupported... */

- default:
- pt_error_return(regs, EIO);
+ default: {
+ int err = ptrace_request(child, request, addr, data);
+ if (err)
+ pt_error_return(regs, -err);
+ else
+ pt_succ_return(regs, 0);
goto out_tsk;
}
+ }
flush_and_out:
{
unsigned long va;
@@ -612,7 +617,8 @@
return;
if (!(current->ptrace & PT_PTRACED))
return;
- current->exit_code = SIGTRAP;
+ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0);
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
diff -Nru a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c
--- a/arch/x86_64/ia32/ptrace32.c Sat Oct 26 20:09:49 2002
+++ b/arch/x86_64/ia32/ptrace32.c Sat Oct 26 20:09:49 2002
@@ -185,17 +185,6 @@
__u32 val;

switch (request) {
- case PTRACE_TRACEME:
- case PTRACE_ATTACH:
- case PTRACE_SYSCALL:
- case PTRACE_CONT:
- case PTRACE_KILL:
- case PTRACE_SINGLESTEP:
- case PTRACE_DETACH:
- case PTRACE_SETOPTIONS:
- ret = sys_ptrace(request, pid, addr, data);
- return ret;
-
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA:
case PTRACE_POKEDATA:
@@ -211,7 +200,8 @@
break;

default:
- return -EIO;
+ ret = sys_ptrace(request, pid, addr, data);
+ return ret;
}

child = find_target(request, pid, &ret);
diff -Nru a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
--- a/arch/x86_64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/arch/x86_64/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -405,17 +405,8 @@
break;
}

- case PTRACE_SETOPTIONS: {
- if (data & PTRACE_O_TRACESYSGOOD)
- child->ptrace |= PT_TRACESYSGOOD;
- else
- child->ptrace &= ~PT_TRACESYSGOOD;
- ret = 0;
- break;
- }
-
default:
- ret = -EIO;
+ ret = ptrace_request(child, request, addr, data);
break;
}
out_tsk:
diff -Nru a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h
--- a/include/asm-arm/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/asm-arm/ptrace.h Sat Oct 26 20:09:49 2002
@@ -6,10 +6,7 @@
#define PTRACE_GETFPREGS 14
#define PTRACE_SETFPREGS 15

-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_OLDSETOPTIONS 21

#include <asm/proc/ptrace.h>

diff -Nru a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h
--- a/include/asm-i386/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/asm-i386/ptrace.h Sat Oct 26 20:09:49 2002
@@ -49,10 +49,7 @@
#define PTRACE_GETFPXREGS 18
#define PTRACE_SETFPXREGS 19

-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_OLDSETOPTIONS 21

#ifdef __KERNEL__
#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
diff -Nru a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h
--- a/include/asm-ia64/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/asm-ia64/ptrace.h Sat Oct 26 20:09:49 2002
@@ -287,9 +287,6 @@
#define PTRACE_GETREGS 18 /* get all registers (pt_all_user_regs) in one shot */
#define PTRACE_SETREGS 19 /* set all registers (pt_all_user_regs) in one shot */

-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_OLDSETOPTIONS 21

#endif /* _ASM_IA64_PTRACE_H */
diff -Nru a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h
--- a/include/asm-mips/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/asm-mips/ptrace.h Sat Oct 26 20:09:49 2002
@@ -59,10 +59,7 @@
/* #define PTRACE_GETFPXREGS 18 */
/* #define PTRACE_SETFPXREGS 19 */

-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_OLDSETOPTIONS 21

#ifdef _LANGUAGE_ASSEMBLY
#include <asm/offset.h>
diff -Nru a/include/asm-mips64/ptrace.h b/include/asm-mips64/ptrace.h
--- a/include/asm-mips64/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/asm-mips64/ptrace.h Sat Oct 26 20:09:49 2002
@@ -64,10 +64,7 @@
/* #define PTRACE_GETFPXREGS 18 */
/* #define PTRACE_SETFPXREGS 19 */

-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_OLDSETOPTIONS 21

#ifdef _LANGUAGE_ASSEMBLY
#include <asm/offset.h>
diff -Nru a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
--- a/include/asm-s390/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/asm-s390/ptrace.h Sat Oct 26 20:09:49 2002
@@ -105,10 +105,7 @@

#define STACK_FRAME_OVERHEAD 96 /* size of minimum stack frame */

-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_OLDSETOPTIONS 21

#ifndef __ASSEMBLY__
#include <linux/config.h>
diff -Nru a/include/asm-s390x/ptrace.h b/include/asm-s390x/ptrace.h
--- a/include/asm-s390x/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/asm-s390x/ptrace.h Sat Oct 26 20:09:49 2002
@@ -85,10 +85,7 @@

#define STACK_FRAME_OVERHEAD 160 /* size of minimum stack frame */

-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_OLDSETOPTIONS 21

#ifndef __ASSEMBLY__
#include <linux/config.h>
diff -Nru a/include/asm-sh/ptrace.h b/include/asm-sh/ptrace.h
--- a/include/asm-sh/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/asm-sh/ptrace.h Sat Oct 26 20:09:49 2002
@@ -44,10 +44,7 @@
#define REG_XDREG14 47
#define REG_FPSCR 48

-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_OLDSETOPTIONS 21

/*
* This struct defines the way the registers are stored on the
diff -Nru a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h
--- a/include/asm-x86_64/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/asm-x86_64/ptrace.h Sat Oct 26 20:09:49 2002
@@ -32,10 +32,7 @@
/* top of stack page */
#define FRAME_SIZE 168

-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_OLDSETOPTIONS 21

/* Dummy values for ptrace */
#define FS 1000
diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h
--- a/include/linux/ptrace.h Sat Oct 26 20:09:49 2002
+++ b/include/linux/ptrace.h Sat Oct 26 20:09:49 2002
@@ -23,6 +23,12 @@

#define PTRACE_SYSCALL 24

+/* 0x4200-0x4300 are reserved for architecture-independent additions. */
+#define PTRACE_SETOPTIONS 0x4200
+
+/* options set using PTRACE_SETOPTIONS */
+#define PTRACE_O_TRACESYSGOOD 0x00000001
+
#include <asm/ptrace.h>
#include <linux/sched.h>

@@ -32,6 +38,7 @@
extern int ptrace_detach(struct task_struct *, unsigned int);
extern void ptrace_disable(struct task_struct *);
extern int ptrace_check_attach(struct task_struct *task, int kill);
+extern int ptrace_request(struct task_struct *child, long request, long addr, long data);
extern void __ptrace_link(struct task_struct *child,
struct task_struct *new_parent);
extern void __ptrace_unlink(struct task_struct *child);
diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c
--- a/kernel/ptrace.c Sat Oct 26 20:09:49 2002
+++ b/kernel/ptrace.c Sat Oct 26 20:09:49 2002
@@ -248,3 +248,35 @@
}
return copied;
}
+
+int ptrace_setoptions(struct task_struct *child, long data)
+{
+ if (data & PTRACE_O_TRACESYSGOOD)
+ child->ptrace |= PT_TRACESYSGOOD;
+ else
+ child->ptrace &= ~PT_TRACESYSGOOD;
+
+ if ((data & PTRACE_O_TRACESYSGOOD) != data)
+ return -EINVAL;
+
+ return 0;
+}
+
+int ptrace_request(struct task_struct *child, long request,
+ long addr, long data)
+{
+ int ret = -EIO;
+
+ switch (request) {
+#ifdef PTRACE_OLDSETOPTIONS
+ case PTRACE_OLDSETOPTIONS:
+#endif
+ case PTRACE_SETOPTIONS:
+ ret = ptrace_setoptions(child, data);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}


--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer


2002-10-27 18:45:28

by Daniel Jacobowitz

[permalink] [raw]
Subject: PATCH: ptrace support for fork/vfork/clone events [2/3]

On Sun, Oct 27, 2002 at 01:50:38PM -0500, Daniel Jacobowitz wrote:
> 2. Add a new clone flag, CLONE_UNTRACED, and force it in all kernel_thread
> implementations. Needed by the next patch. This one touches every
> architecture and some of them in assembly; I've tried to get them all
> correct.

Here's the second one.

[Why is this needed? It's needed so that the debugger doesn't get
triggered on, say, a kernel-started modprobe process or some other
kernel thread. That'd confuse the debugger, beyond the other possible
security/stability problems.]

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.809 -> 1.810
# arch/i386/kernel/process.c 1.32 -> 1.33
# arch/alpha/kernel/entry.S 1.15.1.2 -> 1.17
# arch/x86_64/kernel/process.c 1.7.1.3 -> 1.9
# include/linux/sched.h 1.94.1.14 -> 1.96
# arch/sparc/kernel/process.c 1.18 -> 1.19
# arch/s390x/kernel/process.c 1.10.1.4 -> 1.12
# arch/parisc/kernel/entry.S 1.3 -> 1.5
# arch/mips64/kernel/process.c 1.4 -> 1.5
# arch/ppc64/kernel/misc.S 1.28 -> 1.29
# arch/mips/kernel/process.c 1.7 -> 1.8
# arch/cris/kernel/entry.S 1.12 -> 1.13
# arch/sparc64/kernel/process.c 1.35 -> 1.36
# arch/ia64/kernel/process.c 1.15.1.1 -> 1.17
# arch/m68k/kernel/process.c 1.10 -> 1.11
# arch/cris/kernel/entryoffsets.c 1.3 -> 1.4
# arch/ppc64/kernel/asm-offsets.c 1.11 -> 1.12
# arch/sh/kernel/process.c 1.12 -> 1.13
# arch/s390/kernel/process.c 1.12.1.4 -> 1.14
# arch/arm/kernel/process.c 1.20 -> 1.21
# arch/ppc/kernel/misc.S 1.29 -> 1.30
# arch/alpha/kernel/asm-offsets.c 1.6 -> 1.7
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/26 [email protected] 1.810
# Merge to kernel.org
# --------------------------------------------
#
diff -Nru a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
--- a/arch/alpha/kernel/asm-offsets.c Sat Oct 26 20:09:43 2002
+++ b/arch/alpha/kernel/asm-offsets.c Sat Oct 26 20:09:43 2002
@@ -22,6 +22,7 @@
BLANK();
DEFINE(PT_PTRACED, PT_PTRACED);
DEFINE(CLONE_VM, CLONE_VM);
+ DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
DEFINE(SIGCHLD, SIGCHLD);
BLANK();
DEFINE(HAE_CACHE, offsetof(struct alpha_machine_vector, hae_cache));
diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
--- a/arch/alpha/kernel/entry.S Sat Oct 26 20:09:43 2002
+++ b/arch/alpha/kernel/entry.S Sat Oct 26 20:09:43 2002
@@ -212,7 +212,7 @@
stq $2, 152($30) /* HAE */

/* Shuffle FLAGS to the front; add CLONE_VM. */
- ldi $1, CLONE_VM
+ ldi $1, CLONE_VM|CLONE_UNTRACED
or $18, $1, $16
bsr $26, sys_clone

diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
--- a/arch/arm/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/arm/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -403,7 +403,7 @@
b sys_exit \n\
1: "
: "=r" (__ret)
- : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg)
+ : "Ir" (flags), "r" (CLONE_VM | CLONE_UNTRACED), "r" (fn), "r" (arg)
: "r0", "r1", "lr");
return __ret;
}
diff -Nru a/arch/cris/kernel/entry.S b/arch/cris/kernel/entry.S
--- a/arch/cris/kernel/entry.S Sat Oct 26 20:09:43 2002
+++ b/arch/cris/kernel/entry.S Sat Oct 26 20:09:43 2002
@@ -748,6 +748,7 @@
/* r11 is argument 2 to clone, the flags */
move.d $r12, $r11
or.w LCLONE_VM, $r11
+ or.w LCLONE_UNTRACED, $r11

/* Save FN for later. */
move.d $r10, $r12
diff -Nru a/arch/cris/kernel/entryoffsets.c b/arch/cris/kernel/entryoffsets.c
--- a/arch/cris/kernel/entryoffsets.c Sat Oct 26 20:09:43 2002
+++ b/arch/cris/kernel/entryoffsets.c Sat Oct 26 20:09:43 2002
@@ -57,5 +57,6 @@

/* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these. */
VAL (LCLONE_VM, CLONE_VM)
+VAL (LCLONE_UNTRACED, CLONE_UNTRACED)

__asm__ (".endif");
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/i386/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -224,7 +224,7 @@
regs.eflags = 0x286;

/* Ok, create the new process.. */
- p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
+ p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}

diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/ia64/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -514,7 +514,7 @@
struct task_struct *parent = current;
int result, tid;

- tid = clone(flags | CLONE_VM, 0);
+ tid = clone(flags | CLONE_VM | CLONE_UNTRACED, 0);
if (parent != current) {
result = (*fn)(arg);
_exit(result);
diff -Nru a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
--- a/arch/m68k/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/m68k/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -152,7 +152,7 @@

{
register long retval __asm__ ("d0");
- register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
+ register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;

retval = __NR_clone;
__asm__ __volatile__
diff -Nru a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
--- a/arch/mips/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/mips/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -176,7 +176,7 @@
:"=r" (retval)
:"i" (__NR_clone), "i" (__NR_exit),
"r" (arg), "r" (fn),
- "r" (flags | CLONE_VM)
+ "r" (flags | CLONE_VM | CLONE_UNTRACED)
/*
* The called subroutine might have destroyed any of the
* at, result, argument or temporary registers ...
diff -Nru a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c
--- a/arch/mips64/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/mips64/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -167,7 +167,7 @@
"1:\tmove\t%0, $2"
:"=r" (retval)
:"i" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn),
- "r" (flags | CLONE_VM)
+ "r" (flags | CLONE_VM | CLONE_UNTRACED)

/* The called subroutine might have destroyed any of the
* at, result, argument or temporary registers ... */
diff -Nru a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
--- a/arch/parisc/kernel/entry.S Sat Oct 26 20:09:43 2002
+++ b/arch/parisc/kernel/entry.S Sat Oct 26 20:09:43 2002
@@ -482,6 +482,7 @@
*/

#define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
+#define CLONE_UNTRACED 0x00800000

.export __kernel_thread, code
.import do_fork
@@ -497,7 +498,8 @@
#endif
STREG %r26, PT_GR26(%r1) /* Store function & argument for child */
STREG %r25, PT_GR25(%r1)
- ldo CLONE_VM(%r0), %r26 /* Force CLONE_VM since only init_mm */
+ ldil L%CLONE_UNTRACED, %r26
+ ldo CLONE_VM(%r26), %r26 /* Force CLONE_VM since only init_mm */
or %r26, %r24, %r26 /* will have kernel mappings. */
copy %r0, %r25
bl do_fork_FIXME_NOW_RETURNS_TASK_STRUCT, %r2
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S Sat Oct 26 20:09:43 2002
+++ b/arch/ppc/kernel/misc.S Sat Oct 26 20:09:43 2002
@@ -1005,6 +1005,7 @@
mr r30,r3 /* function */
mr r31,r4 /* argument */
ori r3,r5,CLONE_VM /* flags */
+ oris r3,r3,CLONE_UNTRACED>>16
li r0,__NR_clone
sc
cmpi 0,r3,0 /* parent or child? */
diff -Nru a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c
--- a/arch/ppc64/kernel/asm-offsets.c Sat Oct 26 20:09:43 2002
+++ b/arch/ppc64/kernel/asm-offsets.c Sat Oct 26 20:09:43 2002
@@ -157,6 +157,7 @@
DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);

DEFINE(CLONE_VM, CLONE_VM);
+ DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);

return 0;
}
diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S Sat Oct 26 20:09:43 2002
+++ b/arch/ppc64/kernel/misc.S Sat Oct 26 20:09:43 2002
@@ -486,6 +486,7 @@
/* XXX fix this when we optimise syscall entry to not save volatiles */
mr r6,r3 /* function */
ori r3,r5,CLONE_VM /* flags */
+ oris r3,r3,(CLONE_UNTRACED>>16)
li r0,__NR_clone
sc
cmpi 0,r3,0 /* parent or child? */
diff -Nru a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
--- a/arch/s390/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/s390/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -146,7 +146,7 @@
regs.orig_gpr2 = -1;

/* Ok, create the new process.. */
- p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
+ p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}

diff -Nru a/arch/s390x/kernel/process.c b/arch/s390x/kernel/process.c
--- a/arch/s390x/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/s390x/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -143,7 +143,7 @@
regs.orig_gpr2 = -1;

/* Ok, create the new process.. */
- p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
+ p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}

diff -Nru a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
--- a/arch/sh/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/sh/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -120,7 +120,7 @@
{ /* Don't use this in BL=1(cli). Or else, CPU resets! */
register unsigned long __sc0 __asm__ ("r0");
register unsigned long __sc3 __asm__ ("r3") = __NR_clone;
- register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM;
+ register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM | CLONE_UNTRACED;
register unsigned long __sc5 __asm__ ("r5") = 0;
register unsigned long __sc8 __asm__ ("r8") = (long) arg;
register unsigned long __sc9 __asm__ ("r9") = (long) fn;
diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
--- a/arch/sparc/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/sparc/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -726,7 +726,7 @@
/* Notreached by child. */
"1: mov %%o0, %0\n\t" :
"=r" (retval) :
- "i" (__NR_clone), "r" (flags | CLONE_VM),
+ "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
"i" (__NR_exit), "r" (fn), "r" (arg) :
"g1", "g2", "g3", "o0", "o1", "memory", "cc");
return retval;
diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
--- a/arch/sparc64/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/sparc64/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -694,7 +694,7 @@
/* Notreached by child. */
"1:" :
"=r" (retval) :
- "i" (__NR_clone), "r" (flags | CLONE_VM),
+ "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
"i" (__NR_exit), "r" (fn), "r" (arg) :
"g1", "g2", "g3", "o0", "o1", "memory", "cc");
return retval;
diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
--- a/arch/x86_64/kernel/process.c Sat Oct 26 20:09:43 2002
+++ b/arch/x86_64/kernel/process.c Sat Oct 26 20:09:43 2002
@@ -59,7 +59,7 @@
asmlinkage extern void ret_from_fork(void);
int sys_arch_prctl(int code, unsigned long addr);

-unsigned long kernel_thread_flags = CLONE_VM;
+unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;

int hlt_counter;

diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h Sat Oct 26 20:09:43 2002
+++ b/include/linux/sched.h Sat Oct 26 20:09:43 2002
@@ -51,6 +51,7 @@
#define CLONE_SETTID 0x00100000 /* write the TID back to userspace */
#define CLONE_CLEARTID 0x00200000 /* clear the userspace TID */
#define CLONE_DETACHED 0x00400000 /* parent wants no child-exit signal */
+#define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */

/*
* List of flags we want to share for kernel threads,


--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer

2002-10-27 18:47:00

by Alan Cox

[permalink] [raw]
Subject: Re: PATCH: ptrace support for fork/vfork/clone events [1/3]

> I've submitted this a couple of times and gotten no feedback, but I'm a
> sucker for pain, so here it is again - I'd really like to see this patch in
> 2.6.

I've been ignoring this because it doesn't appear to agree with what other
people tell me. For example why can't you do the fork trace by building
a trampoline ?

2002-10-27 18:46:26

by Daniel Jacobowitz

[permalink] [raw]
Subject: PATCH: ptrace support for fork/vfork/clone events [3/3]

On Sun, Oct 27, 2002 at 01:50:38PM -0500, Daniel Jacobowitz wrote:
> 3. Add PTRACE_GETEVENTMSG and four new flags to PTRACE_SETOPTIONS, to allow
> tracing fork, vfork, clone, and exec events.

This is the fun one.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.810 -> 1.811
# include/linux/sched.h 1.95.1.1 -> 1.97
# kernel/fork.c 1.77.1.10 -> 1.79
# include/linux/ptrace.h 1.4 -> 1.5
# fs/binfmt_aout.c 1.12.1.1 -> 1.14
# fs/binfmt_elf.c 1.29 -> 1.30
# kernel/ptrace.c 1.19 -> 1.20
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/26 [email protected] 1.811
# Merge
# --------------------------------------------
#
diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c
--- a/fs/binfmt_aout.c Sat Oct 26 20:09:37 2002
+++ b/fs/binfmt_aout.c Sat Oct 26 20:09:37 2002
@@ -425,8 +425,12 @@
regs->gp = ex.a_gpvalue;
#endif
start_thread(regs, ex.a_entry, current->mm->start_stack);
- if (current->ptrace & PT_PTRACED)
- send_sig(SIGTRAP, current, 0);
+ if (unlikely(current->ptrace & PT_PTRACED)) {
+ if (current->ptrace & PT_TRACE_EXEC)
+ ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
+ else
+ send_sig(SIGTRAP, current, 0);
+ }
return 0;
}

diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c Sat Oct 26 20:09:37 2002
+++ b/fs/binfmt_elf.c Sat Oct 26 20:09:37 2002
@@ -792,8 +792,12 @@
#endif

start_thread(regs, elf_entry, bprm->p);
- if (current->ptrace & PT_PTRACED)
- send_sig(SIGTRAP, current, 0);
+ if (unlikely(current->ptrace & PT_PTRACED)) {
+ if (current->ptrace & PT_TRACE_EXEC)
+ ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
+ else
+ send_sig(SIGTRAP, current, 0);
+ }
retval = 0;
out:
return retval;
diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h
--- a/include/linux/ptrace.h Sat Oct 26 20:09:37 2002
+++ b/include/linux/ptrace.h Sat Oct 26 20:09:37 2002
@@ -25,9 +25,20 @@

/* 0x4200-0x4300 are reserved for architecture-independent additions. */
#define PTRACE_SETOPTIONS 0x4200
+#define PTRACE_GETEVENTMSG 0x4201

/* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_O_TRACEFORK 0x00000002
+#define PTRACE_O_TRACEVFORK 0x00000004
+#define PTRACE_O_TRACECLONE 0x00000008
+#define PTRACE_O_TRACEEXEC 0x00000010
+
+/* Wait extended result codes for the above trace options. */
+#define PTRACE_EVENT_FORK 1
+#define PTRACE_EVENT_VFORK 2
+#define PTRACE_EVENT_CLONE 3
+#define PTRACE_EVENT_EXEC 4

#include <asm/ptrace.h>
#include <linux/sched.h>
@@ -39,6 +50,7 @@
extern void ptrace_disable(struct task_struct *);
extern int ptrace_check_attach(struct task_struct *task, int kill);
extern int ptrace_request(struct task_struct *child, long request, long addr, long data);
+extern void ptrace_notify(int exit_code);
extern void __ptrace_link(struct task_struct *child,
struct task_struct *new_parent);
extern void __ptrace_unlink(struct task_struct *child);
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h Sat Oct 26 20:09:37 2002
+++ b/include/linux/sched.h Sat Oct 26 20:09:37 2002
@@ -392,6 +392,8 @@
void *journal_info;
struct dentry *proc_dentry;
struct backing_dev_info *backing_dev_info;
+
+ unsigned long ptrace_message;
};

extern void __put_task_struct(struct task_struct *tsk);
@@ -431,6 +433,10 @@
#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */
#define PT_TRACESYSGOOD 0x00000004
#define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */
+#define PT_TRACE_FORK 0x00000010
+#define PT_TRACE_VFORK 0x00000020
+#define PT_TRACE_CLONE 0x00000040
+#define PT_TRACE_EXEC 0x00000080

/*
* Limit the stack by to some sane default: root can always
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c Sat Oct 26 20:09:37 2002
+++ b/kernel/fork.c Sat Oct 26 20:09:37 2002
@@ -937,6 +937,22 @@
goto fork_out;
}

+static inline int fork_traceflag (unsigned clone_flags)
+{
+ if (clone_flags & (CLONE_UNTRACED | CLONE_IDLETASK))
+ return 0;
+ else if (clone_flags & CLONE_VFORK) {
+ if (current->ptrace & PT_TRACE_VFORK)
+ return PTRACE_EVENT_VFORK;
+ } else if ((clone_flags & CSIGNAL) != SIGCHLD) {
+ if (current->ptrace & PT_TRACE_CLONE)
+ return PTRACE_EVENT_CLONE;
+ } else if (current->ptrace & PT_TRACE_FORK)
+ return PTRACE_EVENT_FORK;
+
+ return 0;
+}
+
/*
* Ok, this is the main fork-routine.
*
@@ -950,6 +966,13 @@
int *user_tid)
{
struct task_struct *p;
+ int trace = 0;
+
+ if (unlikely(current->ptrace)) {
+ trace = fork_traceflag (clone_flags);
+ if (trace)
+ clone_flags |= CLONE_PTRACE;
+ }

p = copy_process(clone_flags, stack_start, regs, stack_size, user_tid);
if (!IS_ERR(p)) {
@@ -965,6 +988,12 @@

wake_up_forked_process(p); /* do this last */
++total_forks;
+
+ if (unlikely (trace)) {
+ current->ptrace_message = (unsigned long) p->pid;
+ ptrace_notify ((trace << 8) | SIGTRAP);
+ }
+
if (clone_flags & CLONE_VFORK)
wait_for_completion(&vfork);
else
diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c
--- a/kernel/ptrace.c Sat Oct 26 20:09:37 2002
+++ b/kernel/ptrace.c Sat Oct 26 20:09:37 2002
@@ -249,14 +249,37 @@
return copied;
}

-int ptrace_setoptions(struct task_struct *child, long data)
+static int ptrace_setoptions(struct task_struct *child, long data)
{
if (data & PTRACE_O_TRACESYSGOOD)
child->ptrace |= PT_TRACESYSGOOD;
else
child->ptrace &= ~PT_TRACESYSGOOD;

- if ((data & PTRACE_O_TRACESYSGOOD) != data)
+ if (data & PTRACE_O_TRACEFORK)
+ child->ptrace |= PT_TRACE_FORK;
+ else
+ child->ptrace &= ~PT_TRACE_FORK;
+
+ if (data & PTRACE_O_TRACEVFORK)
+ child->ptrace |= PT_TRACE_VFORK;
+ else
+ child->ptrace &= ~PT_TRACE_VFORK;
+
+ if (data & PTRACE_O_TRACECLONE)
+ child->ptrace |= PT_TRACE_CLONE;
+ else
+ child->ptrace &= ~PT_TRACE_CLONE;
+
+ if (data & PTRACE_O_TRACEEXEC)
+ child->ptrace |= PT_TRACE_EXEC;
+ else
+ child->ptrace &= ~PT_TRACE_EXEC;
+
+ if ((data & (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK
+ | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE
+ | PTRACE_O_TRACEEXEC))
+ != data)
return -EINVAL;

return 0;
@@ -274,9 +297,23 @@
case PTRACE_SETOPTIONS:
ret = ptrace_setoptions(child, data);
break;
+ case PTRACE_GETEVENTMSG:
+ ret = put_user(child->ptrace_message, (unsigned long *) data);
+ break;
default:
break;
}

return ret;
+}
+
+void ptrace_notify(int exit_code)
+{
+ BUG_ON (!(current->ptrace & PT_PTRACED));
+
+ /* Let the debugger run. */
+ current->exit_code = exit_code;
+ set_current_state(TASK_STOPPED);
+ notify_parent(current, SIGCHLD);
+ schedule();
}


--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer

2002-10-27 18:56:21

by Daniel Jacobowitz

[permalink] [raw]
Subject: Re: PATCH: ptrace support for fork/vfork/clone events [1/3]

On Sun, Oct 27, 2002 at 01:53:17PM -0500, Alan Cox wrote:
> > I've submitted this a couple of times and gotten no feedback, but I'm a
> > sucker for pain, so here it is again - I'd really like to see this patch in
> > 2.6.
>
> I've been ignoring this because it doesn't appear to agree with what other
> people tell me. For example why can't you do the fork trace by building
> a trampoline ?

This is what strace used to do. You'll notice that Red Hat's doesn't
any more - not sure if that's in a release yet, Roland was working on
it. I'm not sure exactly how it works now, but the gist of the problem
was that it's unreliable. I believe the exact problem he was addressing
was that while strace held the process stopped and figured out the
child's PID, the child got a signal. It leaves the trampoline and goes
off to handle the signal; strace loses track of it, and it either exits
(confusing the tracer) or longjmps (completely escaping the tracer).

The trampolines are platform-specific, too, which is a real nuisance.
Some of them are still wrong in the strace source.

Another advantage of ptrace reporting this is that we can stop on these
events without having to manage breakpoints on the syscall points in
libc, which is good when people inline-asm a clone() for some reason;
which does still happen. GDB can't use PTRACE_SYSCALL to find forks,
it's a substantial slowdown for minimal benefit.

I can probably come up with some more reasons if you want :)

--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer

2002-10-30 04:26:51

by Daniel Jacobowitz

[permalink] [raw]
Subject: Re: PATCH: ptrace support for fork/vfork/clone events [1/3]

On Sun, Oct 27, 2002 at 02:03:11PM -0500, Daniel Jacobowitz wrote:
> On Sun, Oct 27, 2002 at 01:53:17PM -0500, Alan Cox wrote:
> > > I've submitted this a couple of times and gotten no feedback, but I'm a
> > > sucker for pain, so here it is again - I'd really like to see this patch in
> > > 2.6.
> >
> > I've been ignoring this because it doesn't appear to agree with what other
> > people tell me. For example why can't you do the fork trace by building
> > a trampoline ?
>
> This is what strace used to do. You'll notice that Red Hat's doesn't
> any more - not sure if that's in a release yet, Roland was working on
> it. I'm not sure exactly how it works now, but the gist of the problem
> was that it's unreliable. I believe the exact problem he was addressing
> was that while strace held the process stopped and figured out the
> child's PID, the child got a signal. It leaves the trampoline and goes
> off to handle the signal; strace loses track of it, and it either exits
> (confusing the tracer) or longjmps (completely escaping the tracer).
>
> The trampolines are platform-specific, too, which is a real nuisance.
> Some of them are still wrong in the strace source.
>
> Another advantage of ptrace reporting this is that we can stop on these
> events without having to manage breakpoints on the syscall points in
> libc, which is good when people inline-asm a clone() for some reason;
> which does still happen. GDB can't use PTRACE_SYSCALL to find forks,
> it's a substantial slowdown for minimal benefit.
>
> I can probably come up with some more reasons if you want :)

Alan, did I manage to convince you this was necessary?

Meanwhile, updated patches to tonight's BK tree are at:
http://crack.them.org/~drow/forks/
and
bk://nevyn.them.org:5000

--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer

2002-10-31 19:55:33

by Daniel Jacobowitz

[permalink] [raw]
Subject: Re: PATCH: ptrace support for fork/vfork/clone events [1/3]

Here's #2.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.856 -> 1.857
# arch/i386/kernel/process.c 1.32 -> 1.33
# arch/alpha/kernel/entry.S 1.15.1.2 -> 1.17
# arch/x86_64/kernel/process.c 1.7.1.3 -> 1.9
# include/linux/sched.h 1.94.1.15 -> 1.97
# arch/sparc/kernel/process.c 1.18 -> 1.19
# arch/parisc/kernel/entry.S 1.3.1.1 -> 1.6
# arch/mips64/kernel/process.c 1.4 -> 1.5
# arch/ppc64/kernel/misc.S 1.28 -> 1.29
# arch/mips/kernel/process.c 1.7 -> 1.8
# arch/cris/kernel/entry.S 1.12 -> 1.13
# arch/sparc64/kernel/process.c 1.35 -> 1.36
# arch/ia64/kernel/process.c 1.15.1.3 -> 1.18
# arch/m68k/kernel/process.c 1.10 -> 1.11
# arch/cris/kernel/entryoffsets.c 1.3 -> 1.4
# arch/ppc64/kernel/asm-offsets.c 1.11 -> 1.12
# arch/sh/kernel/process.c 1.12 -> 1.13
# arch/s390x/kernel/process.c 1.10.1.4 -> 1.12
# arch/s390/kernel/process.c 1.12.1.4 -> 1.14
# arch/arm/kernel/process.c 1.20 -> 1.21
# arch/ppc/kernel/misc.S 1.29 -> 1.30
# arch/alpha/kernel/asm-offsets.c 1.6 -> 1.7
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/31 [email protected] 1.857
# Merge nevyn.them.org:/nevyn/big/kernel/test/linux-2.5-trace1
# into nevyn.them.org:/nevyn/big/kernel/test/linux-2.5-trace2
# --------------------------------------------
#
diff -Nru a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
--- a/arch/alpha/kernel/asm-offsets.c Thu Oct 31 14:02:10 2002
+++ b/arch/alpha/kernel/asm-offsets.c Thu Oct 31 14:02:10 2002
@@ -22,6 +22,7 @@
BLANK();
DEFINE(PT_PTRACED, PT_PTRACED);
DEFINE(CLONE_VM, CLONE_VM);
+ DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
DEFINE(SIGCHLD, SIGCHLD);
BLANK();
DEFINE(HAE_CACHE, offsetof(struct alpha_machine_vector, hae_cache));
diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
--- a/arch/alpha/kernel/entry.S Thu Oct 31 14:02:10 2002
+++ b/arch/alpha/kernel/entry.S Thu Oct 31 14:02:10 2002
@@ -212,7 +212,7 @@
stq $2, 152($30) /* HAE */

/* Shuffle FLAGS to the front; add CLONE_VM. */
- ldi $1, CLONE_VM
+ ldi $1, CLONE_VM|CLONE_UNTRACED
or $18, $1, $16
bsr $26, sys_clone

diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
--- a/arch/arm/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/arm/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -403,7 +403,7 @@
b sys_exit \n\
1: "
: "=r" (__ret)
- : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg)
+ : "Ir" (flags), "r" (CLONE_VM | CLONE_UNTRACED), "r" (fn), "r" (arg)
: "r0", "r1", "lr");
return __ret;
}
diff -Nru a/arch/cris/kernel/entry.S b/arch/cris/kernel/entry.S
--- a/arch/cris/kernel/entry.S Thu Oct 31 14:02:10 2002
+++ b/arch/cris/kernel/entry.S Thu Oct 31 14:02:10 2002
@@ -748,6 +748,7 @@
/* r11 is argument 2 to clone, the flags */
move.d $r12, $r11
or.w LCLONE_VM, $r11
+ or.w LCLONE_UNTRACED, $r11

/* Save FN for later. */
move.d $r10, $r12
diff -Nru a/arch/cris/kernel/entryoffsets.c b/arch/cris/kernel/entryoffsets.c
--- a/arch/cris/kernel/entryoffsets.c Thu Oct 31 14:02:10 2002
+++ b/arch/cris/kernel/entryoffsets.c Thu Oct 31 14:02:10 2002
@@ -57,5 +57,6 @@

/* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these. */
VAL (LCLONE_VM, CLONE_VM)
+VAL (LCLONE_UNTRACED, CLONE_UNTRACED)

__asm__ (".endif");
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/i386/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -224,7 +224,7 @@
regs.eflags = 0x286;

/* Ok, create the new process.. */
- p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
+ p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}

diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/ia64/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -516,7 +516,7 @@
struct task_struct *parent = current;
int result, tid;

- tid = clone(flags | CLONE_VM, 0);
+ tid = clone(flags | CLONE_VM | CLONE_UNTRACED, 0);
if (parent != current) {
result = (*fn)(arg);
_exit(result);
diff -Nru a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
--- a/arch/m68k/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/m68k/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -152,7 +152,7 @@

{
register long retval __asm__ ("d0");
- register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
+ register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;

retval = __NR_clone;
__asm__ __volatile__
diff -Nru a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
--- a/arch/mips/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/mips/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -176,7 +176,7 @@
:"=r" (retval)
:"i" (__NR_clone), "i" (__NR_exit),
"r" (arg), "r" (fn),
- "r" (flags | CLONE_VM)
+ "r" (flags | CLONE_VM | CLONE_UNTRACED)
/*
* The called subroutine might have destroyed any of the
* at, result, argument or temporary registers ...
diff -Nru a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c
--- a/arch/mips64/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/mips64/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -167,7 +167,7 @@
"1:\tmove\t%0, $2"
:"=r" (retval)
:"i" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn),
- "r" (flags | CLONE_VM)
+ "r" (flags | CLONE_VM | CLONE_UNTRACED)

/* The called subroutine might have destroyed any of the
* at, result, argument or temporary registers ... */
diff -Nru a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
--- a/arch/parisc/kernel/entry.S Thu Oct 31 14:02:10 2002
+++ b/arch/parisc/kernel/entry.S Thu Oct 31 14:02:10 2002
@@ -515,6 +515,7 @@
*/

#define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
+#define CLONE_UNTRACED 0x00800000

.export __kernel_thread, code
.import do_fork
@@ -531,7 +532,8 @@
#endif
STREG %r26, PT_GR26(%r1) /* Store function & argument for child */
STREG %r25, PT_GR25(%r1)
- ldo CLONE_VM(%r0), %r26 /* Force CLONE_VM since only init_mm */
+ ldil L%CLONE_UNTRACED, %r26
+ ldo CLONE_VM(%r26), %r26 /* Force CLONE_VM since only init_mm */
or %r26, %r24, %r26 /* will have kernel mappings. */
copy %r0, %r25
#ifdef __LP64__
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S Thu Oct 31 14:02:10 2002
+++ b/arch/ppc/kernel/misc.S Thu Oct 31 14:02:10 2002
@@ -1005,6 +1005,7 @@
mr r30,r3 /* function */
mr r31,r4 /* argument */
ori r3,r5,CLONE_VM /* flags */
+ oris r3,r3,CLONE_UNTRACED>>16
li r0,__NR_clone
sc
cmpi 0,r3,0 /* parent or child? */
diff -Nru a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c
--- a/arch/ppc64/kernel/asm-offsets.c Thu Oct 31 14:02:10 2002
+++ b/arch/ppc64/kernel/asm-offsets.c Thu Oct 31 14:02:10 2002
@@ -157,6 +157,7 @@
DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);

DEFINE(CLONE_VM, CLONE_VM);
+ DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);

return 0;
}
diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S Thu Oct 31 14:02:10 2002
+++ b/arch/ppc64/kernel/misc.S Thu Oct 31 14:02:10 2002
@@ -486,6 +486,7 @@
/* XXX fix this when we optimise syscall entry to not save volatiles */
mr r6,r3 /* function */
ori r3,r5,CLONE_VM /* flags */
+ oris r3,r3,(CLONE_UNTRACED>>16)
li r0,__NR_clone
sc
cmpi 0,r3,0 /* parent or child? */
diff -Nru a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
--- a/arch/s390/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/s390/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -146,7 +146,7 @@
regs.orig_gpr2 = -1;

/* Ok, create the new process.. */
- p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
+ p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}

diff -Nru a/arch/s390x/kernel/process.c b/arch/s390x/kernel/process.c
--- a/arch/s390x/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/s390x/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -143,7 +143,7 @@
regs.orig_gpr2 = -1;

/* Ok, create the new process.. */
- p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
+ p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}

diff -Nru a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
--- a/arch/sh/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/sh/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -120,7 +120,7 @@
{ /* Don't use this in BL=1(cli). Or else, CPU resets! */
register unsigned long __sc0 __asm__ ("r0");
register unsigned long __sc3 __asm__ ("r3") = __NR_clone;
- register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM;
+ register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM | CLONE_UNTRACED;
register unsigned long __sc5 __asm__ ("r5") = 0;
register unsigned long __sc8 __asm__ ("r8") = (long) arg;
register unsigned long __sc9 __asm__ ("r9") = (long) fn;
diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
--- a/arch/sparc/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/sparc/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -726,7 +726,7 @@
/* Notreached by child. */
"1: mov %%o0, %0\n\t" :
"=r" (retval) :
- "i" (__NR_clone), "r" (flags | CLONE_VM),
+ "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
"i" (__NR_exit), "r" (fn), "r" (arg) :
"g1", "g2", "g3", "o0", "o1", "memory", "cc");
return retval;
diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
--- a/arch/sparc64/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/sparc64/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -694,7 +694,7 @@
/* Notreached by child. */
"1:" :
"=r" (retval) :
- "i" (__NR_clone), "r" (flags | CLONE_VM),
+ "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
"i" (__NR_exit), "r" (fn), "r" (arg) :
"g1", "g2", "g3", "o0", "o1", "memory", "cc");
return retval;
diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
--- a/arch/x86_64/kernel/process.c Thu Oct 31 14:02:10 2002
+++ b/arch/x86_64/kernel/process.c Thu Oct 31 14:02:10 2002
@@ -59,7 +59,7 @@
asmlinkage extern void ret_from_fork(void);
int sys_arch_prctl(int code, unsigned long addr);

-unsigned long kernel_thread_flags = CLONE_VM;
+unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;

int hlt_counter;

diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h Thu Oct 31 14:02:10 2002
+++ b/include/linux/sched.h Thu Oct 31 14:02:10 2002
@@ -51,6 +51,7 @@
#define CLONE_SETTID 0x00100000 /* write the TID back to userspace */
#define CLONE_CLEARTID 0x00200000 /* clear the userspace TID */
#define CLONE_DETACHED 0x00400000 /* parent wants no child-exit signal */
+#define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */

/*
* List of flags we want to share for kernel threads,


--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer

2002-10-31 19:57:04

by Daniel Jacobowitz

[permalink] [raw]
Subject: Re: PATCH: ptrace support for fork/vfork/clone events [1/3]

And the interesting one, #3.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.857 -> 1.858
# include/linux/sched.h 1.95.1.2 -> 1.98
# kernel/fork.c 1.77.1.12 -> 1.81
# include/linux/ptrace.h 1.4 -> 1.5
# fs/binfmt_aout.c 1.12.1.1 -> 1.14
# fs/binfmt_elf.c 1.29 -> 1.30
# kernel/ptrace.c 1.19 -> 1.20
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/31 [email protected] 1.858
# Merge nevyn.them.org:/nevyn/big/kernel/test/linux-2.5-trace2
# into nevyn.them.org:/nevyn/big/kernel/test/linux-2.5-trace3
# --------------------------------------------
#
diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c
--- a/fs/binfmt_aout.c Thu Oct 31 14:02:04 2002
+++ b/fs/binfmt_aout.c Thu Oct 31 14:02:04 2002
@@ -425,8 +425,12 @@
regs->gp = ex.a_gpvalue;
#endif
start_thread(regs, ex.a_entry, current->mm->start_stack);
- if (current->ptrace & PT_PTRACED)
- send_sig(SIGTRAP, current, 0);
+ if (unlikely(current->ptrace & PT_PTRACED)) {
+ if (current->ptrace & PT_TRACE_EXEC)
+ ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
+ else
+ send_sig(SIGTRAP, current, 0);
+ }
return 0;
}

diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c Thu Oct 31 14:02:04 2002
+++ b/fs/binfmt_elf.c Thu Oct 31 14:02:04 2002
@@ -792,8 +792,12 @@
#endif

start_thread(regs, elf_entry, bprm->p);
- if (current->ptrace & PT_PTRACED)
- send_sig(SIGTRAP, current, 0);
+ if (unlikely(current->ptrace & PT_PTRACED)) {
+ if (current->ptrace & PT_TRACE_EXEC)
+ ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP);
+ else
+ send_sig(SIGTRAP, current, 0);
+ }
retval = 0;
out:
return retval;
diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h
--- a/include/linux/ptrace.h Thu Oct 31 14:02:04 2002
+++ b/include/linux/ptrace.h Thu Oct 31 14:02:04 2002
@@ -25,9 +25,20 @@

/* 0x4200-0x4300 are reserved for architecture-independent additions. */
#define PTRACE_SETOPTIONS 0x4200
+#define PTRACE_GETEVENTMSG 0x4201

/* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001
+#define PTRACE_O_TRACEFORK 0x00000002
+#define PTRACE_O_TRACEVFORK 0x00000004
+#define PTRACE_O_TRACECLONE 0x00000008
+#define PTRACE_O_TRACEEXEC 0x00000010
+
+/* Wait extended result codes for the above trace options. */
+#define PTRACE_EVENT_FORK 1
+#define PTRACE_EVENT_VFORK 2
+#define PTRACE_EVENT_CLONE 3
+#define PTRACE_EVENT_EXEC 4

#include <asm/ptrace.h>
#include <linux/sched.h>
@@ -39,6 +50,7 @@
extern void ptrace_disable(struct task_struct *);
extern int ptrace_check_attach(struct task_struct *task, int kill);
extern int ptrace_request(struct task_struct *child, long request, long addr, long data);
+extern void ptrace_notify(int exit_code);
extern void __ptrace_link(struct task_struct *child,
struct task_struct *new_parent);
extern void __ptrace_unlink(struct task_struct *child);
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h Thu Oct 31 14:02:04 2002
+++ b/include/linux/sched.h Thu Oct 31 14:02:04 2002
@@ -389,6 +389,8 @@
void *journal_info;
struct dentry *proc_dentry;
struct backing_dev_info *backing_dev_info;
+
+ unsigned long ptrace_message;
};

extern void __put_task_struct(struct task_struct *tsk);
@@ -427,6 +429,10 @@
#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */
#define PT_TRACESYSGOOD 0x00000004
#define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */
+#define PT_TRACE_FORK 0x00000010
+#define PT_TRACE_VFORK 0x00000020
+#define PT_TRACE_CLONE 0x00000040
+#define PT_TRACE_EXEC 0x00000080

/*
* Limit the stack by to some sane default: root can always
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c Thu Oct 31 14:02:04 2002
+++ b/kernel/fork.c Thu Oct 31 14:02:04 2002
@@ -943,6 +943,22 @@
goto fork_out;
}

+static inline int fork_traceflag (unsigned clone_flags)
+{
+ if (clone_flags & (CLONE_UNTRACED | CLONE_IDLETASK))
+ return 0;
+ else if (clone_flags & CLONE_VFORK) {
+ if (current->ptrace & PT_TRACE_VFORK)
+ return PTRACE_EVENT_VFORK;
+ } else if ((clone_flags & CSIGNAL) != SIGCHLD) {
+ if (current->ptrace & PT_TRACE_CLONE)
+ return PTRACE_EVENT_CLONE;
+ } else if (current->ptrace & PT_TRACE_FORK)
+ return PTRACE_EVENT_FORK;
+
+ return 0;
+}
+
/*
* Ok, this is the main fork-routine.
*
@@ -956,6 +972,13 @@
int *user_tid)
{
struct task_struct *p;
+ int trace = 0;
+
+ if (unlikely(current->ptrace)) {
+ trace = fork_traceflag (clone_flags);
+ if (trace)
+ clone_flags |= CLONE_PTRACE;
+ }

p = copy_process(clone_flags, stack_start, regs, stack_size, user_tid);
if (!IS_ERR(p)) {
@@ -971,6 +994,12 @@

wake_up_forked_process(p); /* do this last */
++total_forks;
+
+ if (unlikely (trace)) {
+ current->ptrace_message = (unsigned long) p->pid;
+ ptrace_notify ((trace << 8) | SIGTRAP);
+ }
+
if (clone_flags & CLONE_VFORK)
wait_for_completion(&vfork);
else
diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c
--- a/kernel/ptrace.c Thu Oct 31 14:02:04 2002
+++ b/kernel/ptrace.c Thu Oct 31 14:02:04 2002
@@ -249,14 +249,37 @@
return copied;
}

-int ptrace_setoptions(struct task_struct *child, long data)
+static int ptrace_setoptions(struct task_struct *child, long data)
{
if (data & PTRACE_O_TRACESYSGOOD)
child->ptrace |= PT_TRACESYSGOOD;
else
child->ptrace &= ~PT_TRACESYSGOOD;

- if ((data & PTRACE_O_TRACESYSGOOD) != data)
+ if (data & PTRACE_O_TRACEFORK)
+ child->ptrace |= PT_TRACE_FORK;
+ else
+ child->ptrace &= ~PT_TRACE_FORK;
+
+ if (data & PTRACE_O_TRACEVFORK)
+ child->ptrace |= PT_TRACE_VFORK;
+ else
+ child->ptrace &= ~PT_TRACE_VFORK;
+
+ if (data & PTRACE_O_TRACECLONE)
+ child->ptrace |= PT_TRACE_CLONE;
+ else
+ child->ptrace &= ~PT_TRACE_CLONE;
+
+ if (data & PTRACE_O_TRACEEXEC)
+ child->ptrace |= PT_TRACE_EXEC;
+ else
+ child->ptrace &= ~PT_TRACE_EXEC;
+
+ if ((data & (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK
+ | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE
+ | PTRACE_O_TRACEEXEC))
+ != data)
return -EINVAL;

return 0;
@@ -274,9 +297,23 @@
case PTRACE_SETOPTIONS:
ret = ptrace_setoptions(child, data);
break;
+ case PTRACE_GETEVENTMSG:
+ ret = put_user(child->ptrace_message, (unsigned long *) data);
+ break;
default:
break;
}

return ret;
+}
+
+void ptrace_notify(int exit_code)
+{
+ BUG_ON (!(current->ptrace & PT_PTRACED));
+
+ /* Let the debugger run. */
+ current->exit_code = exit_code;
+ set_current_state(TASK_STOPPED);
+ notify_parent(current, SIGCHLD);
+ schedule();
}


--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer