diff options
Diffstat (limited to 'runtime/task_finder.c')
-rw-r--r-- | runtime/task_finder.c | 109 |
1 files changed, 79 insertions, 30 deletions
diff --git a/runtime/task_finder.c b/runtime/task_finder.c index a8de13d0..9b03234d 100644 --- a/runtime/task_finder.c +++ b/runtime/task_finder.c @@ -239,6 +239,7 @@ __stp_utrace_attach(struct task_struct *tsk, static inline void __stp_utrace_attach_match_filename(struct task_struct *tsk, const char * const filename, + int register_p, unsigned long event_flag) { size_t filelen; @@ -272,8 +273,8 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk, continue; if (cb_tgt->callback != NULL) { - int rc = cb_tgt->callback(tsk, 1, event_flag, - cb_tgt); + int rc = cb_tgt->callback(tsk, register_p, + event_flag, cb_tgt); if (rc != 0) { _stp_error("callback for %d failed: %d", (int)tsk->pid, rc); @@ -282,64 +283,102 @@ __stp_utrace_attach_match_filename(struct task_struct *tsk, } // Set up thread death notification. - rc = __stp_utrace_attach(tsk, &cb_tgt->ops, cb_tgt, - __STP_UTRACE_ATTACHED_TASK_EVENTS); - if (rc != 0 && rc != EPERM) - break; - cb_tgt->engine_attached = 1; + if (register_p) { + rc = __stp_utrace_attach(tsk, &cb_tgt->ops, + cb_tgt, + __STP_UTRACE_ATTACHED_TASK_EVENTS); + if (rc != 0 && rc != EPERM) + break; + cb_tgt->engine_attached = 1; + } + else { + struct utrace_attached_engine *engine; + engine = utrace_attach(tsk, + UTRACE_ATTACH_MATCH_OPS, + &cb_tgt->ops, 0); + if (! IS_ERR(engine) && engine != NULL) { + utrace_detach(tsk, engine); + } + } } } } -static u32 -__stp_utrace_task_finder_report_clone(struct utrace_attached_engine *engine, - struct task_struct *parent, - unsigned long clone_flags, - struct task_struct *child) +// This function handles the details of getting a task's associated +// pathname, and calling __stp_utrace_attach_match_filename() to +// attach to it if we find the pathname "interesting". So, what's the +// difference between path_tsk and match_tsk? Normally they are the +// same, except in one case. In an UTRACE_EVENT(EXEC), we need to +// detach engines from the newly exec'ed process (since its path has +// changed). In this case, we have to match the path of the parent +// (path_tsk) against the child (match_tsk). + +static void +__stp_utrace_attach_match_tsk(struct task_struct *path_tsk, + struct task_struct *match_tsk, int register_p, + unsigned long event_flag) { - int rc; struct mm_struct *mm; char *mmpath_buf; char *mmpath; - if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) - return UTRACE_ACTION_RESUME; + if (path_tsk->pid <= 1 || match_tsk->pid <= 1) + return; - // On clone, attach to the child. - rc = __stp_utrace_attach(child, engine->ops, 0, - __STP_UTRACE_TASK_FINDER_EVENTS); - if (rc != 0 && rc != EPERM) - return UTRACE_ACTION_RESUME; - - /* Grab the path associated with this task. */ - mm = get_task_mm(child); + /* Grab the path associated with the path_tsk. */ + mm = get_task_mm(path_tsk); if (! mm) { /* If the thread doesn't have a mm_struct, it is * a kernel thread which we need to skip. */ - return UTRACE_ACTION_RESUME; + return; } // Allocate space for a path mmpath_buf = _stp_kmalloc(PATH_MAX); if (mmpath_buf == NULL) { + mmput(mm); _stp_error("Unable to allocate space for path"); - return UTRACE_ACTION_RESUME; + return; } // Grab the path associated with the new task mmpath = __stp_get_mm_path(mm, mmpath_buf, PATH_MAX); mmput(mm); /* We're done with mm */ if (mmpath == NULL || IS_ERR(mmpath)) { - rc = -PTR_ERR(mmpath); + int rc = -PTR_ERR(mmpath); _stp_error("Unable to get path (error %d) for pid %d", - rc, (int)child->pid); + rc, (int)path_tsk->pid); } else { - __stp_utrace_attach_match_filename(child, mmpath, - UTRACE_EVENT(CLONE)); + __stp_utrace_attach_match_filename(match_tsk, mmpath, + register_p, event_flag); } _stp_kfree(mmpath_buf); + return; +} + +static u32 +__stp_utrace_task_finder_report_clone(struct utrace_attached_engine *engine, + struct task_struct *parent, + unsigned long clone_flags, + struct task_struct *child) +{ + int rc; + struct mm_struct *mm; + char *mmpath_buf; + char *mmpath; + + if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) + return UTRACE_ACTION_RESUME; + + // On clone, attach to the child. + rc = __stp_utrace_attach(child, engine->ops, 0, + __STP_UTRACE_TASK_FINDER_EVENTS); + if (rc != 0 && rc != EPERM) + return UTRACE_ACTION_RESUME; + + __stp_utrace_attach_match_tsk(parent, child, 1, UTRACE_EVENT(CLONE)); return UTRACE_ACTION_RESUME; } @@ -357,11 +396,21 @@ __stp_utrace_task_finder_report_exec(struct utrace_attached_engine *engine, if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) return UTRACE_ACTION_RESUME; + // When exec'ing, we need to let callers detach from the + // parent thread (if necessary). For instance, assume + // '/bin/bash' clones and then execs '/bin/ls'. If the user + // was probing '/bin/bash', the cloned thread is still + // '/bin/bash' up until the exec. + if (tsk != NULL && tsk->parent != NULL && tsk->parent->pid > 1) { + __stp_utrace_attach_match_tsk(tsk->parent, tsk, 0, + UTRACE_EVENT(EXEC)); + } + // On exec, check bprm if (bprm->filename == NULL) return UTRACE_ACTION_RESUME; - __stp_utrace_attach_match_filename(tsk, bprm->filename, + __stp_utrace_attach_match_filename(tsk, bprm->filename, 1, UTRACE_EVENT(EXEC)); return UTRACE_ACTION_RESUME; |