Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 256849
b: refs/heads/master
c: 4b9d33e
h: refs/heads/master
i:
  256847: 069d60f
v: v3
  • Loading branch information
Tejun Heo authored and Oleg Nesterov committed Jun 22, 2011
1 parent e8a4593 commit 0ca7047
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 132 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a288eecce5253cc1565d400a52b9b476a157e040
refs/heads/master: 4b9d33e6d83cc05a8005a8f9a8b9677fa0f53626
7 changes: 6 additions & 1 deletion trunk/fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,12 @@ int check_unsafe_exec(struct linux_binprm *bprm)
unsigned n_fs;
int res = 0;

bprm->unsafe = tracehook_unsafe_exec(p);
if (p->ptrace) {
if (p->ptrace & PT_PTRACE_CAP)
bprm->unsafe |= LSM_UNSAFE_PTRACE_CAP;
else
bprm->unsafe |= LSM_UNSAFE_PTRACE;
}

n_fs = 1;
spin_lock(&p->fs->lock);
Expand Down
121 changes: 0 additions & 121 deletions trunk/include/linux/tracehook.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,27 +129,6 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
ptrace_report_syscall(regs);
}

/**
* tracehook_unsafe_exec - check for exec declared unsafe due to tracing
* @task: current task doing exec
*
* Return %LSM_UNSAFE_* bits applied to an exec because of tracing.
*
* @task->signal->cred_guard_mutex is held by the caller through the do_execve().
*/
static inline int tracehook_unsafe_exec(struct task_struct *task)
{
int unsafe = 0;
int ptrace = task->ptrace;
if (ptrace & PT_PTRACED) {
if (ptrace & PT_PTRACE_CAP)
unsafe |= LSM_UNSAFE_PTRACE_CAP;
else
unsafe |= LSM_UNSAFE_PTRACE;
}
return unsafe;
}

/**
* tracehook_tracer_task - return the task that is tracing the given task
* @tsk: task to consider
Expand All @@ -168,106 +147,6 @@ static inline struct task_struct *tracehook_tracer_task(struct task_struct *tsk)
return NULL;
}

/**
* tracehook_prepare_clone - prepare for new child to be cloned
* @clone_flags: %CLONE_* flags from clone/fork/vfork system call
*
* This is called before a new user task is to be cloned.
* Its return value will be passed to tracehook_finish_clone().
*
* Called with no locks held.
*/
static inline int tracehook_prepare_clone(unsigned clone_flags)
{
int event = 0;

if (clone_flags & CLONE_UNTRACED)
return 0;

if (clone_flags & CLONE_VFORK)
event = PTRACE_EVENT_VFORK;
else if ((clone_flags & CSIGNAL) != SIGCHLD)
event = PTRACE_EVENT_CLONE;
else
event = PTRACE_EVENT_FORK;

return ptrace_event_enabled(current, event) ? event : 0;
}

/**
* tracehook_finish_clone - new child created and being attached
* @child: new child task
* @clone_flags: %CLONE_* flags from clone/fork/vfork system call
* @trace: return value from tracehook_prepare_clone()
*
* This is called immediately after adding @child to its parent's children list.
* The @trace value is that returned by tracehook_prepare_clone().
*
* Called with current's siglock and write_lock_irq(&tasklist_lock) held.
*/
static inline void tracehook_finish_clone(struct task_struct *child,
unsigned long clone_flags, int trace)
{
ptrace_init_task(child, (clone_flags & CLONE_PTRACE) || trace);
}

/**
* tracehook_report_clone - in parent, new child is about to start running
* @regs: parent's user register state
* @clone_flags: flags from parent's system call
* @pid: new child's PID in the parent's namespace
* @child: new child task
*
* Called after a child is set up, but before it has been started running.
* This is not a good place to block, because the child has not started
* yet. Suspend the child here if desired, and then block in
* tracehook_report_clone_complete(). This must prevent the child from
* self-reaping if tracehook_report_clone_complete() uses the @child
* pointer; otherwise it might have died and been released by the time
* tracehook_report_clone_complete() is called.
*
* Called with no locks held, but the child cannot run until this returns.
*/
static inline void tracehook_report_clone(struct pt_regs *regs,
unsigned long clone_flags,
pid_t pid, struct task_struct *child)
{
if (unlikely(child->ptrace)) {
/*
* It doesn't matter who attached/attaching to this
* task, the pending SIGSTOP is right in any case.
*/
sigaddset(&child->pending.signal, SIGSTOP);
set_tsk_thread_flag(child, TIF_SIGPENDING);
}
}

/**
* tracehook_report_clone_complete - new child is running
* @trace: return value from tracehook_prepare_clone()
* @regs: parent's user register state
* @clone_flags: flags from parent's system call
* @pid: new child's PID in the parent's namespace
* @child: child task, already running
*
* This is called just after the child has started running. This is
* just before the clone/fork syscall returns, or blocks for vfork
* child completion if @clone_flags has the %CLONE_VFORK bit set.
* The @child pointer may be invalid if a self-reaping child died and
* tracehook_report_clone() took no action to prevent it from self-reaping.
*
* Called with no locks held.
*/
static inline void tracehook_report_clone_complete(int trace,
struct pt_regs *regs,
unsigned long clone_flags,
pid_t pid,
struct task_struct *child)
{
if (unlikely(trace))
ptrace_event(trace, pid);
}

/**
* tracehook_signal_handler - signal handler setup is complete
* @sig: number of signal being delivered
Expand Down
41 changes: 32 additions & 9 deletions trunk/kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -1340,7 +1340,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
}

if (likely(p->pid)) {
tracehook_finish_clone(p, clone_flags, trace);
ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);

if (thread_group_leader(p)) {
if (is_child_reaper(pid))
Expand Down Expand Up @@ -1481,10 +1481,22 @@ long do_fork(unsigned long clone_flags,
}

/*
* When called from kernel_thread, don't do user tracing stuff.
* Determine whether and which event to report to ptracer. When
* called from kernel_thread or CLONE_UNTRACED is explicitly
* requested, no event is reported; otherwise, report if the event
* for the type of forking is enabled.
*/
if (likely(user_mode(regs)))
trace = tracehook_prepare_clone(clone_flags);
if (likely(user_mode(regs)) && !(clone_flags & CLONE_UNTRACED)) {
if (clone_flags & CLONE_VFORK)
trace = PTRACE_EVENT_VFORK;
else if ((clone_flags & CSIGNAL) != SIGCHLD)
trace = PTRACE_EVENT_CLONE;
else
trace = PTRACE_EVENT_FORK;

if (likely(!ptrace_event_enabled(current, trace)))
trace = 0;
}

p = copy_process(clone_flags, stack_start, regs, stack_size,
child_tidptr, NULL, trace);
Expand All @@ -1508,20 +1520,31 @@ long do_fork(unsigned long clone_flags,
}

audit_finish_fork(p);
tracehook_report_clone(regs, clone_flags, nr, p);

/*
* Child is ready but hasn't started running yet. Queue
* SIGSTOP if it's gonna be ptraced - it doesn't matter who
* attached/attaching to this task, the pending SIGSTOP is
* right in any case.
*/
if (unlikely(p->ptrace)) {
sigaddset(&p->pending.signal, SIGSTOP);
set_tsk_thread_flag(p, TIF_SIGPENDING);
}

/*
* 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.
* hasn't finished SIGSTOP raising yet. Now we clear it
* and set the child going.
*/
p->flags &= ~PF_STARTING;

wake_up_new_task(p);

tracehook_report_clone_complete(trace, regs,
clone_flags, nr, p);
/* forking complete and child started to run, tell ptracer */
if (unlikely(trace))
ptrace_event(trace, nr);

if (clone_flags & CLONE_VFORK) {
freezer_do_not_count();
Expand Down

0 comments on commit 0ca7047

Please sign in to comment.