|
@@ -37,6 +37,7 @@
|
|
#include <linux/swap.h>
|
|
#include <linux/swap.h>
|
|
#include <linux/syscalls.h>
|
|
#include <linux/syscalls.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/jiffies.h>
|
|
|
|
+#include <linux/tracehook.h>
|
|
#include <linux/futex.h>
|
|
#include <linux/futex.h>
|
|
#include <linux/task_io_accounting_ops.h>
|
|
#include <linux/task_io_accounting_ops.h>
|
|
#include <linux/rcupdate.h>
|
|
#include <linux/rcupdate.h>
|
|
@@ -865,8 +866,7 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p)
|
|
|
|
|
|
new_flags &= ~PF_SUPERPRIV;
|
|
new_flags &= ~PF_SUPERPRIV;
|
|
new_flags |= PF_FORKNOEXEC;
|
|
new_flags |= PF_FORKNOEXEC;
|
|
- if (!(clone_flags & CLONE_PTRACE))
|
|
|
|
- p->ptrace = 0;
|
|
|
|
|
|
+ new_flags |= PF_STARTING;
|
|
p->flags = new_flags;
|
|
p->flags = new_flags;
|
|
clear_freeze_flag(p);
|
|
clear_freeze_flag(p);
|
|
}
|
|
}
|
|
@@ -907,7 +907,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|
struct pt_regs *regs,
|
|
struct pt_regs *regs,
|
|
unsigned long stack_size,
|
|
unsigned long stack_size,
|
|
int __user *child_tidptr,
|
|
int __user *child_tidptr,
|
|
- struct pid *pid)
|
|
|
|
|
|
+ struct pid *pid,
|
|
|
|
+ int trace)
|
|
{
|
|
{
|
|
int retval;
|
|
int retval;
|
|
struct task_struct *p;
|
|
struct task_struct *p;
|
|
@@ -1163,8 +1164,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|
*/
|
|
*/
|
|
p->group_leader = p;
|
|
p->group_leader = p;
|
|
INIT_LIST_HEAD(&p->thread_group);
|
|
INIT_LIST_HEAD(&p->thread_group);
|
|
- INIT_LIST_HEAD(&p->ptrace_entry);
|
|
|
|
- INIT_LIST_HEAD(&p->ptraced);
|
|
|
|
|
|
|
|
/* Now that the task is set up, run cgroup callbacks if
|
|
/* Now that the task is set up, run cgroup callbacks if
|
|
* necessary. We need to run them before the task is visible
|
|
* necessary. We need to run them before the task is visible
|
|
@@ -1195,7 +1194,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|
p->real_parent = current->real_parent;
|
|
p->real_parent = current->real_parent;
|
|
else
|
|
else
|
|
p->real_parent = current;
|
|
p->real_parent = current;
|
|
- p->parent = p->real_parent;
|
|
|
|
|
|
|
|
spin_lock(¤t->sighand->siglock);
|
|
spin_lock(¤t->sighand->siglock);
|
|
|
|
|
|
@@ -1237,8 +1235,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|
|
|
|
|
if (likely(p->pid)) {
|
|
if (likely(p->pid)) {
|
|
list_add_tail(&p->sibling, &p->real_parent->children);
|
|
list_add_tail(&p->sibling, &p->real_parent->children);
|
|
- if (unlikely(p->ptrace & PT_PTRACED))
|
|
|
|
- __ptrace_link(p, current->parent);
|
|
|
|
|
|
+ tracehook_finish_clone(p, clone_flags, trace);
|
|
|
|
|
|
if (thread_group_leader(p)) {
|
|
if (thread_group_leader(p)) {
|
|
if (clone_flags & CLONE_NEWPID)
|
|
if (clone_flags & CLONE_NEWPID)
|
|
@@ -1323,29 +1320,13 @@ struct task_struct * __cpuinit fork_idle(int cpu)
|
|
struct pt_regs regs;
|
|
struct pt_regs regs;
|
|
|
|
|
|
task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL,
|
|
task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL,
|
|
- &init_struct_pid);
|
|
|
|
|
|
+ &init_struct_pid, 0);
|
|
if (!IS_ERR(task))
|
|
if (!IS_ERR(task))
|
|
init_idle(task, cpu);
|
|
init_idle(task, cpu);
|
|
|
|
|
|
return task;
|
|
return task;
|
|
}
|
|
}
|
|
|
|
|
|
-static int fork_traceflag(unsigned clone_flags)
|
|
|
|
-{
|
|
|
|
- if (clone_flags & CLONE_UNTRACED)
|
|
|
|
- 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.
|
|
* Ok, this is the main fork-routine.
|
|
*
|
|
*
|
|
@@ -1380,14 +1361,14 @@ long do_fork(unsigned long clone_flags,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (unlikely(current->ptrace)) {
|
|
|
|
- trace = fork_traceflag (clone_flags);
|
|
|
|
- if (trace)
|
|
|
|
- clone_flags |= CLONE_PTRACE;
|
|
|
|
- }
|
|
|
|
|
|
+ /*
|
|
|
|
+ * When called from kernel_thread, don't do user tracing stuff.
|
|
|
|
+ */
|
|
|
|
+ if (likely(user_mode(regs)))
|
|
|
|
+ trace = tracehook_prepare_clone(clone_flags);
|
|
|
|
|
|
p = copy_process(clone_flags, stack_start, regs, stack_size,
|
|
p = copy_process(clone_flags, stack_start, regs, stack_size,
|
|
- child_tidptr, NULL);
|
|
|
|
|
|
+ child_tidptr, NULL, trace);
|
|
/*
|
|
/*
|
|
* Do this prior waking up the new thread - the thread pointer
|
|
* Do this prior waking up the new thread - the thread pointer
|
|
* might get invalid after that point, if the thread exits quickly.
|
|
* might get invalid after that point, if the thread exits quickly.
|
|
@@ -1405,24 +1386,30 @@ long do_fork(unsigned long clone_flags,
|
|
init_completion(&vfork);
|
|
init_completion(&vfork);
|
|
}
|
|
}
|
|
|
|
|
|
- if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) {
|
|
|
|
|
|
+ tracehook_report_clone(trace, regs, clone_flags, nr, p);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We set PF_STARTING at creation in case tracing wants to
|
|
|
|
+ * use this to distinguish a fully live task from one that
|
|
|
|
+ * hasn't gotten to tracehook_report_clone() yet. Now we
|
|
|
|
+ * clear it and set the child going.
|
|
|
|
+ */
|
|
|
|
+ p->flags &= ~PF_STARTING;
|
|
|
|
+
|
|
|
|
+ if (unlikely(clone_flags & CLONE_STOPPED)) {
|
|
/*
|
|
/*
|
|
* We'll start up with an immediate SIGSTOP.
|
|
* We'll start up with an immediate SIGSTOP.
|
|
*/
|
|
*/
|
|
sigaddset(&p->pending.signal, SIGSTOP);
|
|
sigaddset(&p->pending.signal, SIGSTOP);
|
|
set_tsk_thread_flag(p, TIF_SIGPENDING);
|
|
set_tsk_thread_flag(p, TIF_SIGPENDING);
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!(clone_flags & CLONE_STOPPED))
|
|
|
|
- wake_up_new_task(p, clone_flags);
|
|
|
|
- else
|
|
|
|
__set_task_state(p, TASK_STOPPED);
|
|
__set_task_state(p, TASK_STOPPED);
|
|
-
|
|
|
|
- if (unlikely (trace)) {
|
|
|
|
- current->ptrace_message = nr;
|
|
|
|
- ptrace_notify ((trace << 8) | SIGTRAP);
|
|
|
|
|
|
+ } else {
|
|
|
|
+ wake_up_new_task(p, clone_flags);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ tracehook_report_clone_complete(trace, regs,
|
|
|
|
+ clone_flags, nr, p);
|
|
|
|
+
|
|
if (clone_flags & CLONE_VFORK) {
|
|
if (clone_flags & CLONE_VFORK) {
|
|
freezer_do_not_count();
|
|
freezer_do_not_count();
|
|
wait_for_completion(&vfork);
|
|
wait_for_completion(&vfork);
|