aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-06-17 10:50:38 -0400
committerOleg Nesterov <oleg@redhat.com>2011-06-22 13:26:29 -0400
commit4b9d33e6d83cc05a8005a8f9a8b9677fa0f53626 (patch)
tree250b740d22f9604326ecfd769dd2f74d60187a19
parenta288eecce5253cc1565d400a52b9b476a157e040 (diff)
ptrace: kill clone/exec tracehooks
At this point, tracehooks aren't useful to mainline kernel and mostly just add an extra layer of obfuscation. Although they have comments, without actual in-kernel users, it is difficult to tell what are their assumptions and they're actually trying to achieve. To mainline kernel, they just aren't worth keeping around. This patch kills the following clone and exec related tracehooks. tracehook_prepare_clone() tracehook_finish_clone() tracehook_report_clone() tracehook_report_clone_complete() tracehook_unsafe_exec() The changes are mostly trivial - logic is moved to the caller and comments are merged and adjusted appropriately. The only exception is in check_unsafe_exec() where LSM_UNSAFE_PTRACE* are OR'd to bprm->unsafe instead of setting it, which produces the same result as the field is always zero on entry. It also tests p->ptrace instead of (p->ptrace & PT_PTRACED) for consistency, which also gives the same result. This doesn't introduce any behavior change. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Christoph Hellwig <hch@infradead.org> Signed-off-by: Oleg Nesterov <oleg@redhat.com>
-rw-r--r--fs/exec.c7
-rw-r--r--include/linux/tracehook.h121
-rw-r--r--kernel/fork.c41
3 files changed, 38 insertions, 131 deletions
diff --git a/fs/exec.c b/fs/exec.c
index b37030d0a50b..8dca45b0dae8 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1224,7 +1224,12 @@ int check_unsafe_exec(struct linux_binprm *bprm)
1224 unsigned n_fs; 1224 unsigned n_fs;
1225 int res = 0; 1225 int res = 0;
1226 1226
1227 bprm->unsafe = tracehook_unsafe_exec(p); 1227 if (p->ptrace) {
1228 if (p->ptrace & PT_PTRACE_CAP)
1229 bprm->unsafe |= LSM_UNSAFE_PTRACE_CAP;
1230 else
1231 bprm->unsafe |= LSM_UNSAFE_PTRACE;
1232 }
1228 1233
1229 n_fs = 1; 1234 n_fs = 1;
1230 spin_lock(&p->fs->lock); 1235 spin_lock(&p->fs->lock);
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index 8b06d4f2b814..bcc4ca762aee 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -130,27 +130,6 @@ static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
130} 130}
131 131
132/** 132/**
133 * tracehook_unsafe_exec - check for exec declared unsafe due to tracing
134 * @task: current task doing exec
135 *
136 * Return %LSM_UNSAFE_* bits applied to an exec because of tracing.
137 *
138 * @task->signal->cred_guard_mutex is held by the caller through the do_execve().
139 */
140static inline int tracehook_unsafe_exec(struct task_struct *task)
141{
142 int unsafe = 0;
143 int ptrace = task->ptrace;
144 if (ptrace & PT_PTRACED) {
145 if (ptrace & PT_PTRACE_CAP)
146 unsafe |= LSM_UNSAFE_PTRACE_CAP;
147 else
148 unsafe |= LSM_UNSAFE_PTRACE;
149 }
150 return unsafe;
151}
152
153/**
154 * tracehook_tracer_task - return the task that is tracing the given task 133 * tracehook_tracer_task - return the task that is tracing the given task
155 * @tsk: task to consider 134 * @tsk: task to consider
156 * 135 *
@@ -169,106 +148,6 @@ static inline struct task_struct *tracehook_tracer_task(struct task_struct *tsk)
169} 148}
170 149
171/** 150/**
172 * tracehook_prepare_clone - prepare for new child to be cloned
173 * @clone_flags: %CLONE_* flags from clone/fork/vfork system call
174 *
175 * This is called before a new user task is to be cloned.
176 * Its return value will be passed to tracehook_finish_clone().
177 *
178 * Called with no locks held.
179 */
180static inline int tracehook_prepare_clone(unsigned clone_flags)
181{
182 int event = 0;
183
184 if (clone_flags & CLONE_UNTRACED)
185 return 0;
186
187 if (clone_flags & CLONE_VFORK)
188 event = PTRACE_EVENT_VFORK;
189 else if ((clone_flags & CSIGNAL) != SIGCHLD)
190 event = PTRACE_EVENT_CLONE;
191 else
192 event = PTRACE_EVENT_FORK;
193
194 return ptrace_event_enabled(current, event) ? event : 0;
195}
196
197/**
198 * tracehook_finish_clone - new child created and being attached
199 * @child: new child task
200 * @clone_flags: %CLONE_* flags from clone/fork/vfork system call
201 * @trace: return value from tracehook_prepare_clone()
202 *
203 * This is called immediately after adding @child to its parent's children list.
204 * The @trace value is that returned by tracehook_prepare_clone().
205 *
206 * Called with current's siglock and write_lock_irq(&tasklist_lock) held.
207 */
208static inline void tracehook_finish_clone(struct task_struct *child,
209 unsigned long clone_flags, int trace)
210{
211 ptrace_init_task(child, (clone_flags & CLONE_PTRACE) || trace);
212}
213
214/**
215 * tracehook_report_clone - in parent, new child is about to start running
216 * @regs: parent's user register state
217 * @clone_flags: flags from parent's system call
218 * @pid: new child's PID in the parent's namespace
219 * @child: new child task
220 *
221 * Called after a child is set up, but before it has been started running.
222 * This is not a good place to block, because the child has not started
223 * yet. Suspend the child here if desired, and then block in
224 * tracehook_report_clone_complete(). This must prevent the child from
225 * self-reaping if tracehook_report_clone_complete() uses the @child
226 * pointer; otherwise it might have died and been released by the time
227 * tracehook_report_clone_complete() is called.
228 *
229 * Called with no locks held, but the child cannot run until this returns.
230 */
231static inline void tracehook_report_clone(struct pt_regs *regs,
232 unsigned long clone_flags,
233 pid_t pid, struct task_struct *child)
234{
235 if (unlikely(child->ptrace)) {
236 /*
237 * It doesn't matter who attached/attaching to this
238 * task, the pending SIGSTOP is right in any case.
239 */
240 sigaddset(&child->pending.signal, SIGSTOP);
241 set_tsk_thread_flag(child, TIF_SIGPENDING);
242 }
243}
244
245/**
246 * tracehook_report_clone_complete - new child is running
247 * @trace: return value from tracehook_prepare_clone()
248 * @regs: parent's user register state
249 * @clone_flags: flags from parent's system call
250 * @pid: new child's PID in the parent's namespace
251 * @child: child task, already running
252 *
253 * This is called just after the child has started running. This is
254 * just before the clone/fork syscall returns, or blocks for vfork
255 * child completion if @clone_flags has the %CLONE_VFORK bit set.
256 * The @child pointer may be invalid if a self-reaping child died and
257 * tracehook_report_clone() took no action to prevent it from self-reaping.
258 *
259 * Called with no locks held.
260 */
261static inline void tracehook_report_clone_complete(int trace,
262 struct pt_regs *regs,
263 unsigned long clone_flags,
264 pid_t pid,
265 struct task_struct *child)
266{
267 if (unlikely(trace))
268 ptrace_event(trace, pid);
269}
270
271/**
272 * tracehook_signal_handler - signal handler setup is complete 151 * tracehook_signal_handler - signal handler setup is complete
273 * @sig: number of signal being delivered 152 * @sig: number of signal being delivered
274 * @info: siginfo_t of signal being delivered 153 * @info: siginfo_t of signal being delivered
diff --git a/kernel/fork.c b/kernel/fork.c
index d4f0dff9d617..3c72a5b321a7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1340,7 +1340,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1340 } 1340 }
1341 1341
1342 if (likely(p->pid)) { 1342 if (likely(p->pid)) {
1343 tracehook_finish_clone(p, clone_flags, trace); 1343 ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
1344 1344
1345 if (thread_group_leader(p)) { 1345 if (thread_group_leader(p)) {
1346 if (is_child_reaper(pid)) 1346 if (is_child_reaper(pid))
@@ -1481,10 +1481,22 @@ long do_fork(unsigned long clone_flags,
1481 } 1481 }
1482 1482
1483 /* 1483 /*
1484 * When called from kernel_thread, don't do user tracing stuff. 1484 * Determine whether and which event to report to ptracer. When
1485 * called from kernel_thread or CLONE_UNTRACED is explicitly
1486 * requested, no event is reported; otherwise, report if the event
1487 * for the type of forking is enabled.
1485 */ 1488 */
1486 if (likely(user_mode(regs))) 1489 if (likely(user_mode(regs)) && !(clone_flags & CLONE_UNTRACED)) {
1487 trace = tracehook_prepare_clone(clone_flags); 1490 if (clone_flags & CLONE_VFORK)
1491 trace = PTRACE_EVENT_VFORK;
1492 else if ((clone_flags & CSIGNAL) != SIGCHLD)
1493 trace = PTRACE_EVENT_CLONE;
1494 else
1495 trace = PTRACE_EVENT_FORK;
1496
1497 if (likely(!ptrace_event_enabled(current, trace)))
1498 trace = 0;
1499 }
1488 1500
1489 p = copy_process(clone_flags, stack_start, regs, stack_size, 1501 p = copy_process(clone_flags, stack_start, regs, stack_size,
1490 child_tidptr, NULL, trace); 1502 child_tidptr, NULL, trace);
@@ -1508,20 +1520,31 @@ long do_fork(unsigned long clone_flags,
1508 } 1520 }
1509 1521
1510 audit_finish_fork(p); 1522 audit_finish_fork(p);
1511 tracehook_report_clone(regs, clone_flags, nr, p); 1523
1524 /*
1525 * Child is ready but hasn't started running yet. Queue
1526 * SIGSTOP if it's gonna be ptraced - it doesn't matter who
1527 * attached/attaching to this task, the pending SIGSTOP is
1528 * right in any case.
1529 */
1530 if (unlikely(p->ptrace)) {
1531 sigaddset(&p->pending.signal, SIGSTOP);
1532 set_tsk_thread_flag(p, TIF_SIGPENDING);
1533 }
1512 1534
1513 /* 1535 /*
1514 * We set PF_STARTING at creation in case tracing wants to 1536 * We set PF_STARTING at creation in case tracing wants to
1515 * use this to distinguish a fully live task from one that 1537 * use this to distinguish a fully live task from one that
1516 * hasn't gotten to tracehook_report_clone() yet. Now we 1538 * hasn't finished SIGSTOP raising yet. Now we clear it
1517 * clear it and set the child going. 1539 * and set the child going.
1518 */ 1540 */
1519 p->flags &= ~PF_STARTING; 1541 p->flags &= ~PF_STARTING;
1520 1542
1521 wake_up_new_task(p); 1543 wake_up_new_task(p);
1522 1544
1523 tracehook_report_clone_complete(trace, regs, 1545 /* forking complete and child started to run, tell ptracer */
1524 clone_flags, nr, p); 1546 if (unlikely(trace))
1547 ptrace_event(trace, nr);
1525 1548
1526 if (clone_flags & CLONE_VFORK) { 1549 if (clone_flags & CLONE_VFORK) {
1527 freezer_do_not_count(); 1550 freezer_do_not_count();