diff options
-rw-r--r-- | fs/exec.c | 7 | ||||
-rw-r--r-- | include/linux/tracehook.h | 121 | ||||
-rw-r--r-- | kernel/fork.c | 41 |
3 files changed, 38 insertions, 131 deletions
@@ -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 8b06d4f2b81..bcc4ca762ae 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 | */ | ||
140 | static 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 | */ | ||
180 | static 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 | */ | ||
208 | static 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 | */ | ||
231 | static 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 | */ | ||
261 | static 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 d4f0dff9d61..3c72a5b321a 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(); |