X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Futrace.c;fp=kernel%2Futrace.c;h=52d9b0059958abb5df9f3c8a4e7397fbac5f8069;hb=f05f9504c50ed069377d37f02f22e7a16b5921de;hp=0000000000000000000000000000000000000000;hpb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;p=linux-2.6.git diff --git a/kernel/utrace.c b/kernel/utrace.c new file mode 100644 index 000000000..52d9b0059 --- /dev/null +++ b/kernel/utrace.c @@ -0,0 +1,1598 @@ +#include +#include +#include +#include +#include +#include +#include +#include + + +static kmem_cache_t *utrace_cachep; +static kmem_cache_t *utrace_engine_cachep; + +static int __init +utrace_init(void) +{ + utrace_cachep = + kmem_cache_create("utrace_cache", + sizeof(struct utrace), 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + utrace_engine_cachep = + kmem_cache_create("utrace_engine_cache", + sizeof(struct utrace_attached_engine), 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + return 0; +} +subsys_initcall(utrace_init); + + +/* + * Make sure target->utrace is allocated, and return with it locked on + * success. This function mediates startup races. The creating parent + * task has priority, and other callers will delay here to let its call + * succeed and take the new utrace lock first. + */ +static struct utrace * +utrace_first_engine(struct task_struct *target, + struct utrace_attached_engine *engine) +{ + struct utrace *utrace, *ret; + + /* + * If this is a newborn thread and we are not the creator, + * we have to wait for it. The creator gets the first chance + * to attach. The PF_STARTING flag is cleared after its + * report_clone hook has had a chance to run. + */ + if ((target->flags & PF_STARTING) + && (current->utrace == NULL + || current->utrace->u.live.cloning != target)) { + yield(); + return (signal_pending(current) + ? ERR_PTR(-ERESTARTNOINTR) : NULL); + } + + utrace = kmem_cache_alloc(utrace_cachep, SLAB_KERNEL); + if (unlikely(utrace == NULL)) + return ERR_PTR(-ENOMEM); + + utrace->u.live.cloning = NULL; + utrace->u.live.signal = NULL; + INIT_LIST_HEAD(&utrace->engines); + list_add(&engine->entry, &utrace->engines); + spin_lock_init(&utrace->lock); + + ret = utrace; + utrace_lock(utrace); + task_lock(target); + if (likely(target->utrace == NULL)) { + rcu_assign_pointer(target->utrace, utrace); + /* + * The task_lock protects us against another thread doing + * the same thing. We might still be racing against + * tracehook_release_task. It's called with ->exit_state + * set to EXIT_DEAD and then checks ->utrace with an + * smp_mb() in between. If EXIT_DEAD is set, then + * release_task might have checked ->utrace already and saw + * it NULL; we can't attach. If we see EXIT_DEAD not yet + * set after our barrier, then we know release_task will + * see our target->utrace pointer. + */ + smp_mb(); + if (target->exit_state == EXIT_DEAD) { + /* + * The target has already been through release_task. + */ + target->utrace = NULL; + goto cannot_attach; + } + task_unlock(target); + + /* + * If the thread is already dead when we attach, then its + * parent was notified already and we shouldn't repeat the + * notification later after a detach or NOREAP flag change. + */ + if (target->exit_state) + utrace->u.exit.notified = 1; + } + else { + /* + * Another engine attached first, so there is a struct already. + * A null return says to restart looking for the existing one. + */ + cannot_attach: + ret = NULL; + task_unlock(target); + utrace_unlock(utrace); + kmem_cache_free(utrace_cachep, utrace); + } + + return ret; +} + +static void +utrace_free(struct rcu_head *rhead) +{ + struct utrace *utrace = container_of(rhead, struct utrace, u.dead); + kmem_cache_free(utrace_cachep, utrace); +} + +static void +rcu_utrace_free(struct utrace *utrace) +{ + INIT_RCU_HEAD(&utrace->u.dead); + call_rcu(&utrace->u.dead, utrace_free); +} + +static void +utrace_engine_free(struct rcu_head *rhead) +{ + struct utrace_attached_engine *engine = + container_of(rhead, struct utrace_attached_engine, rhead); + kmem_cache_free(utrace_engine_cachep, engine); +} + +/* + * Called with utrace locked and the target quiescent (maybe current). + * If this was the last engine, utrace is left locked and not freed, + * but is removed from the task. + */ +static void +remove_engine(struct utrace_attached_engine *engine, + struct task_struct *tsk, struct utrace *utrace) +{ + list_del_rcu(&engine->entry); + if (list_empty(&utrace->engines)) { + task_lock(tsk); + if (likely(tsk->utrace != NULL)) { + rcu_assign_pointer(tsk->utrace, NULL); + tsk->utrace_flags = 0; + } + task_unlock(tsk); + } + call_rcu(&engine->rhead, utrace_engine_free); +} + +/* + * This is pointed to by the utrace struct, but it's really a private + * structure between utrace_get_signal and utrace_inject_signal. + */ +struct utrace_signal +{ + siginfo_t *const info; + struct k_sigaction *return_ka; + int signr; +}; + +/* + * Called with utrace locked, after remove_engine may have run. + * Passed the flags from all remaining engines, i.e. zero if none left. + * Install the flags in tsk->utrace_flags and return with utrace unlocked. + * If no engines are left, utrace is freed and we return NULL. + */ +static struct utrace * +check_dead_utrace(struct task_struct *tsk, struct utrace *utrace, + unsigned long flags) +{ + if (flags) { + tsk->utrace_flags = flags; + utrace_unlock(utrace); + return utrace; + } + + if (utrace->u.live.signal && utrace->u.live.signal->signr != 0) { + utrace_unlock(utrace); + return utrace; + } + + utrace_unlock(utrace); + rcu_utrace_free(utrace); + return NULL; +} + + + +/* + * Get the target thread to quiesce. Return nonzero if it's already quiescent. + * Return zero if it will report a QUIESCE event soon. + * If interrupt is nonzero, wake it like a signal would so it quiesces ASAP. + * If interrupt is zero, just make sure it quiesces before going to user mode. + */ +static int +quiesce(struct task_struct *target, int interrupt) +{ + int quiescent; + + target->utrace_flags |= UTRACE_ACTION_QUIESCE; + read_barrier_depends(); + + quiescent = (target->exit_state + || target->state & (TASK_TRACED | TASK_STOPPED)); + + if (!quiescent) { + spin_lock_irq(&target->sighand->siglock); + quiescent = (unlikely(target->exit_state) + || unlikely(target->state + & (TASK_TRACED | TASK_STOPPED))); + if (!quiescent) { + if (interrupt) + signal_wake_up(target, 0); + else { + set_tsk_thread_flag(target, TIF_SIGPENDING); + kick_process(target); + } + } + spin_unlock_irq(&target->sighand->siglock); + } + + return quiescent; +} + + +static struct utrace_attached_engine * +matching_engine(struct utrace *utrace, int flags, + const struct utrace_engine_ops *ops, unsigned long data) +{ + struct utrace_attached_engine *engine; + list_for_each_entry_rcu(engine, &utrace->engines, entry) { + if ((flags & UTRACE_ATTACH_MATCH_OPS) + && engine->ops != ops) + continue; + if ((flags & UTRACE_ATTACH_MATCH_DATA) + && engine->data != data) + continue; + if (flags & UTRACE_ATTACH_EXCLUSIVE) + engine = ERR_PTR(-EEXIST); + return engine; + } + return NULL; +} + +/* + option to stop it? + option to match existing on ops, ops+data, return it; nocreate:lookup only + */ +struct utrace_attached_engine * +utrace_attach(struct task_struct *target, int flags, + const struct utrace_engine_ops *ops, unsigned long data) +{ + struct utrace *utrace; + struct utrace_attached_engine *engine; + +restart: + rcu_read_lock(); + utrace = rcu_dereference(target->utrace); + smp_rmb(); + if (utrace == NULL) { + rcu_read_unlock(); + + if (!(flags & UTRACE_ATTACH_CREATE)) { + return ERR_PTR(-ENOENT); + } + + engine = kmem_cache_alloc(utrace_engine_cachep, SLAB_KERNEL); + if (unlikely(engine == NULL)) + return ERR_PTR(-ENOMEM); + engine->flags = 0; + + first: + utrace = utrace_first_engine(target, engine); + if (IS_ERR(utrace)) { + kmem_cache_free(utrace_engine_cachep, engine); + return ERR_PTR(PTR_ERR(utrace)); + } + if (unlikely(utrace == NULL)) /* Race condition. */ + goto restart; + } + else if (unlikely(target->exit_state == EXIT_DEAD)) { + /* + * The target has already been reaped. + */ + rcu_read_unlock(); + return ERR_PTR(-ESRCH); + } + else { + if (!(flags & UTRACE_ATTACH_CREATE)) { + engine = matching_engine(utrace, flags, ops, data); + rcu_read_unlock(); + return engine; + } + + engine = kmem_cache_alloc(utrace_engine_cachep, SLAB_KERNEL); + if (unlikely(engine == NULL)) + return ERR_PTR(-ENOMEM); + engine->flags = ops->report_reap ? UTRACE_EVENT(REAP) : 0; + + rcu_read_lock(); + utrace = rcu_dereference(target->utrace); + if (unlikely(utrace == NULL)) { /* Race with detach. */ + rcu_read_unlock(); + goto first; + } + + utrace_lock(utrace); + if (flags & UTRACE_ATTACH_EXCLUSIVE) { + struct utrace_attached_engine *old; + old = matching_engine(utrace, flags, ops, data); + if (old != NULL) { + utrace_unlock(utrace); + rcu_read_unlock(); + kmem_cache_free(utrace_engine_cachep, engine); + return ERR_PTR(-EEXIST); + } + } + + if (unlikely(rcu_dereference(target->utrace) != utrace)) { + /* + * We lost a race with other CPUs doing a sequence + * of detach and attach before we got in. + */ + utrace_unlock(utrace); + rcu_read_unlock(); + kmem_cache_free(utrace_engine_cachep, engine); + goto restart; + } + list_add_tail_rcu(&engine->entry, &utrace->engines); + } + + engine->ops = ops; + engine->data = data; + + utrace_unlock(utrace); + + return engine; +} +EXPORT_SYMBOL_GPL(utrace_attach); + +/* + * When an engine is detached, the target thread may still see it and make + * callbacks until it quiesces. We reset its event flags to just QUIESCE + * and install a special ops vector whose callback is dead_engine_delete. + * When the target thread quiesces, it can safely free the engine itself. + */ +static u32 +dead_engine_delete(struct utrace_attached_engine *engine, + struct task_struct *tsk) +{ + return UTRACE_ACTION_DETACH; +} + +static const struct utrace_engine_ops dead_engine_ops = +{ + .report_quiesce = &dead_engine_delete +}; + + +/* + * If tracing was preventing a SIGCHLD or self-reaping + * and is no longer, do that report or reaping right now. + */ +static void +check_noreap(struct task_struct *target, struct utrace *utrace, + u32 old_action, u32 action) +{ + if ((action | ~old_action) & UTRACE_ACTION_NOREAP) + return; + + if (utrace && xchg(&utrace->u.exit.notified, 1)) + return; + + if (target->exit_signal == -1) + release_task(target); + else if (thread_group_empty(target)) { + read_lock(&tasklist_lock); + do_notify_parent(target, target->exit_signal); + read_unlock(&tasklist_lock); + } +} + +/* + * We may have been the one keeping the target thread quiescent. + * Check if it should wake up now. + * Called with utrace locked, and unlocks it on return. + * If we were keeping it stopped, resume it. + * If we were keeping its zombie from reporting/self-reap, do it now. + */ +static void +wake_quiescent(unsigned long old_flags, + struct utrace *utrace, struct task_struct *target) +{ + unsigned long flags; + struct utrace_attached_engine *engine; + + if (target->exit_state) { + /* + * Update the set of events of interest from the union + * of the interests of the remaining tracing engines. + */ + flags = 0; + list_for_each_entry(engine, &utrace->engines, entry) + flags |= engine->flags | UTRACE_EVENT(REAP); + utrace = check_dead_utrace(target, utrace, flags); + + check_noreap(target, utrace, old_flags, flags); + return; + } + + /* + * Update the set of events of interest from the union + * of the interests of the remaining tracing engines. + */ + flags = 0; + list_for_each_entry(engine, &utrace->engines, entry) + flags |= engine->flags | UTRACE_EVENT(REAP); + utrace = check_dead_utrace(target, utrace, flags); + + if (flags & UTRACE_ACTION_QUIESCE) + return; + + read_lock(&tasklist_lock); + if (!target->exit_state) { + /* + * The target is not dead and should not be in tracing stop + * any more. Wake it unless it's in job control stop. + */ + spin_lock_irq(&target->sighand->siglock); + if (target->signal->flags & SIGNAL_STOP_STOPPED) { + int stop_count = target->signal->group_stop_count; + target->state = TASK_STOPPED; + spin_unlock_irq(&target->sighand->siglock); + + /* + * If tracing was preventing a CLD_STOPPED report + * and is no longer, do that report right now. + */ + if (stop_count == 0 + && 0 + /*&& (events &~ interest) & UTRACE_INHIBIT_CLDSTOP*/ + ) + do_notify_parent_cldstop(target, CLD_STOPPED); + } + else { + /* + * Wake the task up. + */ + recalc_sigpending_tsk(target); + wake_up_state(target, TASK_STOPPED | TASK_TRACED); + spin_unlock_irq(&target->sighand->siglock); + } + } + read_unlock(&tasklist_lock); +} + +void +utrace_detach(struct task_struct *target, + struct utrace_attached_engine *engine) +{ + struct utrace *utrace; + unsigned long flags; + + rcu_read_lock(); + utrace = rcu_dereference(target->utrace); + smp_rmb(); + if (unlikely(target->exit_state == EXIT_DEAD)) { + /* + * Called after utrace_release_task might have started. + * A call to this engine's report_reap callback might + * already be in progress or engine might even have been + * freed already. + */ + rcu_read_unlock(); + return; + } + utrace_lock(utrace); + rcu_read_unlock(); + + flags = engine->flags; + engine->flags = UTRACE_EVENT(QUIESCE) | UTRACE_ACTION_QUIESCE; + rcu_assign_pointer(engine->ops, &dead_engine_ops); + + if (quiesce(target, 1)) { + remove_engine(engine, target, utrace); + wake_quiescent(flags, utrace, target); + } + else + utrace_unlock(utrace); +} +EXPORT_SYMBOL_GPL(utrace_detach); + + +/* + * Called with utrace->lock held. + * Notify and clean up all engines, then free utrace. + */ +static void +utrace_reap(struct task_struct *target, struct utrace *utrace) +{ + struct utrace_attached_engine *engine, *next; + const struct utrace_engine_ops *ops; + +restart: + list_for_each_entry_safe(engine, next, &utrace->engines, entry) { + list_del_rcu(&engine->entry); + + /* + * Now nothing else refers to this engine. + */ + if (engine->flags & UTRACE_EVENT(REAP)) { + ops = rcu_dereference(engine->ops); + if (ops != &dead_engine_ops) { + utrace_unlock(utrace); + (*ops->report_reap)(engine, target); + call_rcu(&engine->rhead, utrace_engine_free); + utrace_lock(utrace); + goto restart; + } + } + call_rcu(&engine->rhead, utrace_engine_free); + } + utrace_unlock(utrace); + + rcu_utrace_free(utrace); +} + +/* + * Called by release_task. After this, target->utrace must be cleared. + */ +void +utrace_release_task(struct task_struct *target) +{ + struct utrace *utrace; + + task_lock(target); + utrace = target->utrace; + rcu_assign_pointer(target->utrace, NULL); + task_unlock(target); + + if (unlikely(utrace == NULL)) + return; + + utrace_lock(utrace); + + if (!utrace->u.exit.notified + && (target->utrace_flags & (UTRACE_EVENT(DEATH) + | UTRACE_EVENT(QUIESCE)))) { + /* + * The target will do some final callbacks but hasn't + * finished them yet. We know because it clears these + * event bits after it's done. Instead of cleaning up here + * and requiring utrace_report_death to cope with it, we + * delay the REAP report and the teardown until after the + * target finishes its death reports. + */ + utrace->u.exit.reap = 1; + utrace_unlock(utrace); + } + else + utrace_reap(target, utrace); /* Unlocks and frees. */ +} + + +void +utrace_set_flags(struct task_struct *target, + struct utrace_attached_engine *engine, + unsigned long flags) +{ + struct utrace *utrace; + int report = 0; + unsigned long old_flags, old_utrace_flags; + +#ifdef ARCH_HAS_SINGLE_STEP + if (! ARCH_HAS_SINGLE_STEP) +#endif + WARN_ON(flags & UTRACE_ACTION_SINGLESTEP); +#ifdef ARCH_HAS_BLOCK_STEP + if (! ARCH_HAS_BLOCK_STEP) +#endif + WARN_ON(flags & UTRACE_ACTION_BLOCKSTEP); + + rcu_read_lock(); + utrace = rcu_dereference(target->utrace); + smp_rmb(); + if (unlikely(target->exit_state == EXIT_DEAD)) { + /* + * Race with reaping. + */ + rcu_read_unlock(); + return; + } + + utrace_lock(utrace); + rcu_read_unlock(); + + old_utrace_flags = target->utrace_flags; + old_flags = engine->flags; + engine->flags = flags; + target->utrace_flags |= flags; + + if ((old_flags ^ flags) & UTRACE_ACTION_QUIESCE) { + if (flags & UTRACE_ACTION_QUIESCE) { + report = (quiesce(target, 1) + && (flags & UTRACE_EVENT(QUIESCE))); + utrace_unlock(utrace); + } + else + wake_quiescent(old_flags, utrace, target); + } + else { + /* + * If we're asking for single-stepping or syscall tracing, + * we need to pass through utrace_quiescent before resuming + * in user mode to get those effects, even if the target is + * not going to be quiescent right now. + */ + if (!(target->utrace_flags & UTRACE_ACTION_QUIESCE) + && ((flags &~ old_utrace_flags) + & (UTRACE_ACTION_SINGLESTEP | UTRACE_ACTION_BLOCKSTEP + | UTRACE_EVENT_SYSCALL))) + quiesce(target, 0); + utrace_unlock(utrace); + } + + if (report) /* Already quiescent, won't report itself. */ + (*engine->ops->report_quiesce)(engine, target); +} +EXPORT_SYMBOL_GPL(utrace_set_flags); + +/* + * While running an engine callback, no locks are held. + * If a callback updates its engine's action state, then + * we need to take the utrace lock to install the flags update. + */ +static inline u32 +update_action(struct task_struct *tsk, struct utrace *utrace, + struct utrace_attached_engine *engine, + u32 ret) +{ + if (ret & UTRACE_ACTION_DETACH) + rcu_assign_pointer(engine->ops, &dead_engine_ops); + else if ((ret & UTRACE_ACTION_NEWSTATE) + && ((ret ^ engine->flags) & UTRACE_ACTION_STATE_MASK)) { +#ifdef ARCH_HAS_SINGLE_STEP + if (! ARCH_HAS_SINGLE_STEP) +#endif + WARN_ON(ret & UTRACE_ACTION_SINGLESTEP); +#ifdef ARCH_HAS_BLOCK_STEP + if (! ARCH_HAS_BLOCK_STEP) +#endif + WARN_ON(ret & UTRACE_ACTION_BLOCKSTEP); + utrace_lock(utrace); + /* + * If we're changing something other than just QUIESCE, + * make sure we pass through utrace_quiescent before + * resuming even if we aren't going to stay quiescent. + * That's where we get the correct union of all engines' + * flags after they've finished changing, and apply changes. + */ + if (((ret ^ engine->flags) & (UTRACE_ACTION_STATE_MASK + & ~UTRACE_ACTION_QUIESCE))) + tsk->utrace_flags |= UTRACE_ACTION_QUIESCE; + engine->flags &= ~UTRACE_ACTION_STATE_MASK; + engine->flags |= ret & UTRACE_ACTION_STATE_MASK; + tsk->utrace_flags |= engine->flags; + utrace_unlock(utrace); + } + else + ret |= engine->flags & UTRACE_ACTION_STATE_MASK; + return ret; +} + +#define REPORT(callback, ...) do { \ + u32 ret = (*rcu_dereference(engine->ops)->callback) \ + (engine, tsk, ##__VA_ARGS__); \ + action = update_action(tsk, utrace, engine, ret); \ + } while (0) + + +/* + * Called with utrace->lock held, returns with it released. + */ +static u32 +remove_detached(struct task_struct *tsk, struct utrace *utrace, + struct utrace **utracep, u32 action) +{ + struct utrace_attached_engine *engine, *next; + unsigned long flags; + + flags = 0; + list_for_each_entry_safe(engine, next, &utrace->engines, entry) { + if (engine->ops == &dead_engine_ops) + remove_engine(engine, tsk, utrace); + else + flags |= engine->flags | UTRACE_EVENT(REAP); + } + utrace = check_dead_utrace(tsk, utrace, flags); + if (utracep) + *utracep = utrace; + + flags &= UTRACE_ACTION_STATE_MASK; + return flags | (action & UTRACE_ACTION_OP_MASK); +} + +/* + * Called after an event report loop. Remove any engines marked for detach. + */ +static inline u32 +check_detach(struct task_struct *tsk, u32 action) +{ + if (action & UTRACE_ACTION_DETACH) { + utrace_lock(tsk->utrace); + action = remove_detached(tsk, tsk->utrace, NULL, action); + } + return action; +} + +static inline void +check_quiescent(struct task_struct *tsk, u32 action) +{ + if (action & UTRACE_ACTION_STATE_MASK) + utrace_quiescent(tsk); +} + +/* + * Called iff UTRACE_EVENT(CLONE) flag is set. + * This notification call blocks the wake_up_new_task call on the child. + * So we must not quiesce here. tracehook_report_clone_complete will do + * a quiescence check momentarily. + */ +void +utrace_report_clone(unsigned long clone_flags, struct task_struct *child) +{ + struct task_struct *tsk = current; + struct utrace *utrace = tsk->utrace; + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + unsigned long action; + + utrace->u.live.cloning = child; + + /* XXX must change for sharing */ + action = UTRACE_ACTION_RESUME; + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + if (engine->flags & UTRACE_EVENT(CLONE)) + REPORT(report_clone, clone_flags, child); + if (action & UTRACE_ACTION_HIDE) + break; + } + + utrace->u.live.cloning = NULL; + + check_detach(tsk, action); +} + +static unsigned long +report_quiescent(struct task_struct *tsk, struct utrace *utrace, u32 action) +{ + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + if (engine->flags & UTRACE_EVENT(QUIESCE)) + REPORT(report_quiesce); + action |= engine->flags & UTRACE_ACTION_STATE_MASK; + } + + return check_detach(tsk, action); +} + +/* + * Called iff UTRACE_EVENT(JCTL) flag is set. + */ +int +utrace_report_jctl(int what) +{ + struct task_struct *tsk = current; + struct utrace *utrace = tsk->utrace; + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + unsigned long action; + + /* XXX must change for sharing */ + action = UTRACE_ACTION_RESUME; + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + if (engine->flags & UTRACE_EVENT(JCTL)) + REPORT(report_jctl, what); + if (action & UTRACE_ACTION_HIDE) + break; + } + + /* + * We are becoming quiescent, so report it now. + * We don't block in utrace_quiescent because we are stopping anyway. + * We know that upon resuming we'll go through tracehook_induce_signal, + * which will keep us quiescent or set us up to resume with tracing. + */ + action = report_quiescent(tsk, utrace, action); + + if (what == CLD_STOPPED && tsk->state != TASK_STOPPED) { + /* + * The event report hooks could have blocked, though + * it should have been briefly. Make sure we're in + * TASK_STOPPED state again to block properly, unless + * we've just come back out of job control stop. + */ + spin_lock_irq(&tsk->sighand->siglock); + if (tsk->signal->flags & SIGNAL_STOP_STOPPED) + set_current_state(TASK_STOPPED); + spin_unlock_irq(&tsk->sighand->siglock); + } + + return action & UTRACE_JCTL_NOSIGCHLD; +} + + +/* + * Called if UTRACE_EVENT(QUIESCE) or UTRACE_ACTION_QUIESCE flag is set. + * Also called after other event reports. + * It is a good time to block. + */ +void +utrace_quiescent(struct task_struct *tsk) +{ + struct utrace *utrace = tsk->utrace; + unsigned long action; + +restart: + /* XXX must change for sharing */ + + action = report_quiescent(tsk, utrace, UTRACE_ACTION_RESUME); + + /* + * If some engines want us quiescent, we block here. + */ + if (action & UTRACE_ACTION_QUIESCE) { + spin_lock_irq(&tsk->sighand->siglock); + /* + * If wake_quiescent is trying to wake us up now, it will + * have cleared the QUIESCE flag before trying to take the + * siglock. Now we have the siglock, so either it has + * already cleared the flag, or it will wake us up after we + * release the siglock it's waiting for. + * Never stop when there is a SIGKILL bringing us down. + */ + if ((tsk->utrace_flags & UTRACE_ACTION_QUIESCE) + /*&& !(tsk->signal->flags & SIGNAL_GROUP_SIGKILL)*/) { + set_current_state(TASK_TRACED); + /* + * If there is a group stop in progress, + * we must participate in the bookkeeping. + */ + if (tsk->signal->group_stop_count > 0) + --tsk->signal->group_stop_count; + spin_unlock_irq(&tsk->sighand->siglock); + schedule(); + } + else + spin_unlock_irq(&tsk->sighand->siglock); + + /* + * We've woken up. One engine could be waking us up while + * another has asked us to quiesce. So check afresh. We + * could have been detached while quiescent. Now we are no + * longer quiescent, so don't need to do any RCU locking. + * But we do need to check our utrace pointer anew. + */ + utrace = tsk->utrace; + if (tsk->utrace_flags + & (UTRACE_EVENT(QUIESCE) | UTRACE_ACTION_STATE_MASK)) + goto restart; + } + else if (tsk->utrace_flags & UTRACE_ACTION_QUIESCE) { + /* + * Our flags are out of date. + * Update the set of events of interest from the union + * of the interests of the remaining tracing engines. + */ + struct utrace_attached_engine *engine; + unsigned long flags = 0; + utrace = rcu_dereference(tsk->utrace); + utrace_lock(utrace); + list_for_each_entry(engine, &utrace->engines, entry) + flags |= engine->flags | UTRACE_EVENT(REAP); + tsk->utrace_flags = flags; + utrace_unlock(utrace); + } + + /* + * We're resuming. Update the machine layer tracing state and then go. + */ +#ifdef ARCH_HAS_SINGLE_STEP + if (action & UTRACE_ACTION_SINGLESTEP) + tracehook_enable_single_step(tsk); + else + tracehook_disable_single_step(tsk); +#endif +#ifdef ARCH_HAS_BLOCK_STEP + if ((action & (UTRACE_ACTION_BLOCKSTEP|UTRACE_ACTION_SINGLESTEP)) + == UTRACE_ACTION_BLOCKSTEP) + tracehook_enable_block_step(tsk); + else + tracehook_disable_block_step(tsk); +#endif + if (tsk->utrace_flags & UTRACE_EVENT_SYSCALL) + tracehook_enable_syscall_trace(tsk); + else + tracehook_disable_syscall_trace(tsk); +} + + +/* + * Called iff UTRACE_EVENT(EXIT) flag is set. + */ +void +utrace_report_exit(long *exit_code) +{ + struct task_struct *tsk = current; + struct utrace *utrace = tsk->utrace; + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + unsigned long action; + long orig_code = *exit_code; + + /* XXX must change for sharing */ + action = UTRACE_ACTION_RESUME; + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + if (engine->flags & UTRACE_EVENT(EXIT)) + REPORT(report_exit, orig_code, exit_code); + } + action = check_detach(tsk, action); + check_quiescent(tsk, action); +} + +/* + * Called iff UTRACE_EVENT(DEATH) flag is set. + * + * It is always possible that we are racing with utrace_release_task here, + * if UTRACE_ACTION_NOREAP is not set, or in the case of non-leader exec + * where the old leader will get released regardless of NOREAP. For this + * reason, utrace_release_task checks for the event bits that get us here, + * and delays its cleanup for us to do. + */ +void +utrace_report_death(struct task_struct *tsk, struct utrace *utrace) +{ + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + u32 action, oaction; + + BUG_ON(!tsk->exit_state); + + oaction = tsk->utrace_flags; + + /* XXX must change for sharing */ + action = UTRACE_ACTION_RESUME; + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + if (engine->flags & UTRACE_EVENT(DEATH)) + REPORT(report_death); + if (engine->flags & UTRACE_EVENT(QUIESCE)) + REPORT(report_quiesce); + } + /* + * Unconditionally lock and recompute the flags. + * This may notice that there are no engines left and + * free the utrace struct. + */ + utrace_lock(utrace); + if (utrace->u.exit.reap) { + /* + * utrace_release_task was already called in parallel. + * We must complete its work now. + */ + reap: + utrace_reap(tsk, utrace); + } + else { + action = remove_detached(tsk, utrace, &utrace, action); + + if (utrace != NULL) { + utrace_lock(utrace); + if (utrace->u.exit.reap) + goto reap; + + /* + * Clear event bits we can't see any more. This + * tells utrace_release_task we have already + * finished, if it comes along later. + */ + tsk->utrace_flags &= (UTRACE_EVENT(REAP) + | UTRACE_ACTION_NOREAP); + + utrace_unlock(utrace); + } + + check_noreap(tsk, utrace, oaction, action); + } +} + +/* + * Called iff UTRACE_EVENT(VFORK_DONE) flag is set. + */ +void +utrace_report_vfork_done(pid_t child_pid) +{ + struct task_struct *tsk = current; + struct utrace *utrace = tsk->utrace; + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + unsigned long action; + + /* XXX must change for sharing */ + action = UTRACE_ACTION_RESUME; + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + if (engine->flags & UTRACE_EVENT(VFORK_DONE)) + REPORT(report_vfork_done, child_pid); + if (action & UTRACE_ACTION_HIDE) + break; + } + action = check_detach(tsk, action); + check_quiescent(tsk, action); +} + +/* + * Called iff UTRACE_EVENT(EXEC) flag is set. + */ +void +utrace_report_exec(struct linux_binprm *bprm, struct pt_regs *regs) +{ + struct task_struct *tsk = current; + struct utrace *utrace = tsk->utrace; + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + unsigned long action; + + /* XXX must change for sharing */ + action = UTRACE_ACTION_RESUME; + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + if (engine->flags & UTRACE_EVENT(EXEC)) + REPORT(report_exec, bprm, regs); + if (action & UTRACE_ACTION_HIDE) + break; + } + action = check_detach(tsk, action); + check_quiescent(tsk, action); +} + +/* + * Called iff UTRACE_EVENT(SYSCALL_{ENTRY,EXIT}) flag is set. + */ +void +utrace_report_syscall(struct pt_regs *regs, int is_exit) +{ + struct task_struct *tsk = current; + struct utrace *utrace = tsk->utrace; + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + unsigned long action, ev; + +/* + XXX pass syscall # to engine hook directly, let it return inhibit-action + to reset to -1 + long syscall = tracehook_syscall_number(regs, is_exit); +*/ + + ev = is_exit ? UTRACE_EVENT(SYSCALL_EXIT) : UTRACE_EVENT(SYSCALL_ENTRY); + + /* XXX must change for sharing */ + action = UTRACE_ACTION_RESUME; + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + if (engine->flags & ev) { + if (is_exit) + REPORT(report_syscall_exit, regs); + else + REPORT(report_syscall_entry, regs); + } + if (action & UTRACE_ACTION_HIDE) + break; + } + action = check_detach(tsk, action); + check_quiescent(tsk, action); +} + +// XXX copied from signal.c +#ifdef SIGEMT +#define M_SIGEMT M(SIGEMT) +#else +#define M_SIGEMT 0 +#endif + +#if SIGRTMIN > BITS_PER_LONG +#define M(sig) (1ULL << ((sig)-1)) +#else +#define M(sig) (1UL << ((sig)-1)) +#endif +#define T(sig, mask) (M(sig) & (mask)) + +#define SIG_KERNEL_ONLY_MASK (\ + M(SIGKILL) | M(SIGSTOP) ) + +#define SIG_KERNEL_STOP_MASK (\ + M(SIGSTOP) | M(SIGTSTP) | M(SIGTTIN) | M(SIGTTOU) ) + +#define SIG_KERNEL_COREDUMP_MASK (\ + M(SIGQUIT) | M(SIGILL) | M(SIGTRAP) | M(SIGABRT) | \ + M(SIGFPE) | M(SIGSEGV) | M(SIGBUS) | M(SIGSYS) | \ + M(SIGXCPU) | M(SIGXFSZ) | M_SIGEMT ) + +#define SIG_KERNEL_IGNORE_MASK (\ + M(SIGCONT) | M(SIGCHLD) | M(SIGWINCH) | M(SIGURG) ) + +#define sig_kernel_only(sig) \ + (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_ONLY_MASK)) +#define sig_kernel_coredump(sig) \ + (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_COREDUMP_MASK)) +#define sig_kernel_ignore(sig) \ + (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_IGNORE_MASK)) +#define sig_kernel_stop(sig) \ + (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_STOP_MASK)) + + +/* + * Call each interested tracing engine's report_signal callback. + */ +static u32 +report_signal(struct task_struct *tsk, struct pt_regs *regs, + struct utrace *utrace, u32 action, + unsigned long flags1, unsigned long flags2, siginfo_t *info, + const struct k_sigaction *ka, struct k_sigaction *return_ka) +{ + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + + /* XXX must change for sharing */ + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + if ((engine->flags & flags1) && (engine->flags & flags2)) { + u32 disp = action & UTRACE_ACTION_OP_MASK; + action &= ~UTRACE_ACTION_OP_MASK; + REPORT(report_signal, regs, disp, info, ka, return_ka); + if ((action & UTRACE_ACTION_OP_MASK) == 0) + action |= disp; + if (action & UTRACE_ACTION_HIDE) + break; + } + } + + return action; +} + +void +utrace_signal_handler_singlestep(struct task_struct *tsk, struct pt_regs *regs) +{ + u32 action; + action = report_signal(tsk, regs, tsk->utrace, UTRACE_SIGNAL_HANDLER, + UTRACE_EVENT_SIGNAL_ALL, + UTRACE_ACTION_SINGLESTEP|UTRACE_ACTION_BLOCKSTEP, + NULL, NULL, NULL); + action = check_detach(tsk, action); + check_quiescent(tsk, action); +} + + +/* + * This is the hook from the signals code, called with the siglock held. + * Here is the ideal place to quiesce. We also dequeue and intercept signals. + */ +int +utrace_get_signal(struct task_struct *tsk, struct pt_regs *regs, + siginfo_t *info, struct k_sigaction *return_ka) +{ + struct utrace *utrace = tsk->utrace; + struct utrace_signal signal = { info, return_ka, 0 }; + struct k_sigaction *ka; + unsigned long action, event; + +#if 0 /* XXX */ + if (tsk->signal->flags & SIGNAL_GROUP_SIGKILL) + return 0; +#endif + + /* + * If we should quiesce, now is the time. + * First stash a pointer to the state on our stack, + * so that utrace_inject_signal can tell us what to do. + */ + if (utrace->u.live.signal == NULL) + utrace->u.live.signal = &signal; + + if (tsk->utrace_flags & UTRACE_ACTION_QUIESCE) { + spin_unlock_irq(&tsk->sighand->siglock); + utrace_quiescent(tsk); + if (signal.signr == 0) + /* + * This return value says to reacquire the siglock + * and check again. This will check for a pending + * group stop and process it before coming back here. + */ + return -1; + spin_lock_irq(&tsk->sighand->siglock); + } + + /* + * If a signal was injected previously, it could not use our + * stack space directly. It had to allocate a data structure, + * which we can now copy out of and free. + */ + if (utrace->u.live.signal != &signal) { + signal.signr = utrace->u.live.signal->signr; + copy_siginfo(info, utrace->u.live.signal->info); + if (utrace->u.live.signal->return_ka) + *return_ka = *utrace->u.live.signal->return_ka; + else + signal.return_ka = NULL; + kfree(utrace->u.live.signal); + } + utrace->u.live.signal = NULL; + + /* + * If a signal was injected, everything is in place now. Go do it. + */ + if (signal.signr != 0) { + if (signal.return_ka == NULL) { + ka = &tsk->sighand->action[signal.signr - 1]; + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + *return_ka = *ka; + } + else + BUG_ON(signal.return_ka != return_ka); + return signal.signr; + } + + /* + * If noone is interested in intercepting signals, let the caller + * just dequeue them normally. + */ + if ((tsk->utrace_flags & UTRACE_EVENT_SIGNAL_ALL) == 0) + return 0; + + /* + * Steal the next signal so we can let tracing engines examine it. + * From the signal number and sigaction, determine what normal + * delivery would do. If no engine perturbs it, we'll do that + * by returning the signal number after setting *return_ka. + */ + signal.signr = dequeue_signal(tsk, &tsk->blocked, info); + if (signal.signr == 0) + return 0; + + BUG_ON(signal.signr != info->si_signo); + + ka = &tsk->sighand->action[signal.signr - 1]; + *return_ka = *ka; + + if (signal.signr == SIGKILL) + return signal.signr; + + if (ka->sa.sa_handler == SIG_IGN) { + event = UTRACE_EVENT(SIGNAL_IGN); + action = UTRACE_SIGNAL_IGN; + } + else if (ka->sa.sa_handler != SIG_DFL) { + event = UTRACE_EVENT(SIGNAL); + action = UTRACE_ACTION_RESUME; + } + else if (sig_kernel_coredump(signal.signr)) { + event = UTRACE_EVENT(SIGNAL_CORE); + action = UTRACE_SIGNAL_CORE; + } + else if (sig_kernel_ignore(signal.signr)) { + event = UTRACE_EVENT(SIGNAL_IGN); + action = UTRACE_SIGNAL_IGN; + } + else if (sig_kernel_stop(signal.signr)) { + event = UTRACE_EVENT(SIGNAL_STOP); + action = (signal.signr == SIGSTOP + ? UTRACE_SIGNAL_STOP : UTRACE_SIGNAL_TSTP); + } + else { + event = UTRACE_EVENT(SIGNAL_TERM); + action = UTRACE_SIGNAL_TERM; + } + + if (tsk->utrace_flags & event) { + /* + * We have some interested engines, so tell them about the + * signal and let them change its disposition. + */ + + spin_unlock_irq(&tsk->sighand->siglock); + + action = report_signal(tsk, regs, utrace, action, event, event, + info, ka, return_ka); + action &= UTRACE_ACTION_OP_MASK; + + if (action & UTRACE_SIGNAL_HOLD) { + struct sigqueue *q = sigqueue_alloc(); + if (likely(q != NULL)) { + q->flags = 0; + copy_siginfo(&q->info, info); + } + action &= ~UTRACE_SIGNAL_HOLD; + spin_lock_irq(&tsk->sighand->siglock); + sigaddset(&tsk->pending.signal, info->si_signo); + if (likely(q != NULL)) + list_add(&q->list, &tsk->pending.list); + } + else + spin_lock_irq(&tsk->sighand->siglock); + + recalc_sigpending_tsk(tsk); + } + + if (tsk->utrace != utrace) + rcu_utrace_free(utrace); + + /* + * We express the chosen action to the signals code in terms + * of a representative signal whose default action does it. + */ + switch (action) { + case UTRACE_SIGNAL_IGN: + /* + * We've eaten the signal. That's all we do. + * Tell the caller to restart. + */ + spin_unlock_irq(&tsk->sighand->siglock); + return -1; + + case UTRACE_ACTION_RESUME: + case UTRACE_SIGNAL_DELIVER: + /* + * The handler will run. We do the SA_ONESHOT work here + * since the normal path will only touch *return_ka now. + */ + if (return_ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + break; + + case UTRACE_SIGNAL_TSTP: + signal.signr = SIGTSTP; + tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; + return_ka->sa.sa_handler = SIG_DFL; + break; + + case UTRACE_SIGNAL_STOP: + signal.signr = SIGSTOP; + tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; + return_ka->sa.sa_handler = SIG_DFL; + break; + + case UTRACE_SIGNAL_TERM: + signal.signr = SIGTERM; + return_ka->sa.sa_handler = SIG_DFL; + break; + + case UTRACE_SIGNAL_CORE: + signal.signr = SIGQUIT; + return_ka->sa.sa_handler = SIG_DFL; + break; + + default: + BUG(); + } + + return signal.signr; +} + + +/* + * Cause a specified signal delivery in the target thread, + * which must be quiescent. The action has UTRACE_SIGNAL_* bits + * as returned from a report_signal callback. If ka is non-null, + * it gives the sigaction to follow for UTRACE_SIGNAL_DELIVER; + * otherwise, the installed sigaction at the time of delivery is used. + */ +int +utrace_inject_signal(struct task_struct *target, + struct utrace_attached_engine *engine, + u32 action, siginfo_t *info, + const struct k_sigaction *ka) +{ + struct utrace *utrace; + struct utrace_signal *signal; + int ret; + + if (info->si_signo == 0 || !valid_signal(info->si_signo)) + return -EINVAL; + + rcu_read_lock(); + utrace = rcu_dereference(target->utrace); + if (utrace == NULL) { + rcu_read_unlock(); + return -ESRCH; + } + utrace_lock(utrace); + rcu_read_unlock(); + + ret = 0; + signal = utrace->u.live.signal; + if (signal == NULL) { + ret = -ENOSYS; /* XXX */ + } + else if (signal->signr != 0) + ret = -EAGAIN; + else { + if (info != signal->info) + copy_siginfo(signal->info, info); + + switch (action) { + default: + ret = -EINVAL; + break; + + case UTRACE_SIGNAL_IGN: + break; + + case UTRACE_ACTION_RESUME: + case UTRACE_SIGNAL_DELIVER: + /* + * The handler will run. We do the SA_ONESHOT work + * here since the normal path will not touch the + * real sigaction when using an injected signal. + */ + if (ka == NULL) + signal->return_ka = NULL; + else if (ka != signal->return_ka) + *signal->return_ka = *ka; + if (ka && ka->sa.sa_flags & SA_ONESHOT) { + struct k_sigaction *a; + a = &target->sighand->action[info->si_signo-1]; + spin_lock_irq(&target->sighand->siglock); + a->sa.sa_handler = SIG_DFL; + spin_unlock_irq(&target->sighand->siglock); + } + signal->signr = info->si_signo; + break; + + case UTRACE_SIGNAL_TSTP: + signal->signr = SIGTSTP; + spin_lock_irq(&target->sighand->siglock); + target->signal->flags |= SIGNAL_STOP_DEQUEUED; + spin_unlock_irq(&target->sighand->siglock); + signal->return_ka->sa.sa_handler = SIG_DFL; + break; + + case UTRACE_SIGNAL_STOP: + signal->signr = SIGSTOP; + spin_lock_irq(&target->sighand->siglock); + target->signal->flags |= SIGNAL_STOP_DEQUEUED; + spin_unlock_irq(&target->sighand->siglock); + signal->return_ka->sa.sa_handler = SIG_DFL; + break; + + case UTRACE_SIGNAL_TERM: + signal->signr = SIGTERM; + signal->return_ka->sa.sa_handler = SIG_DFL; + break; + + case UTRACE_SIGNAL_CORE: + signal->signr = SIGQUIT; + signal->return_ka->sa.sa_handler = SIG_DFL; + break; + } + } + + utrace_unlock(utrace); + + return ret; +} +EXPORT_SYMBOL_GPL(utrace_inject_signal); + + +const struct utrace_regset * +utrace_regset(struct task_struct *target, + struct utrace_attached_engine *engine, + const struct utrace_regset_view *view, int which) +{ + if (unlikely((unsigned) which >= view->n)) + return NULL; + + if (target != current) + wait_task_inactive(target); + + return &view->regsets[which]; +} +EXPORT_SYMBOL_GPL(utrace_regset); + + +/* + * Return the task_struct for the task using ptrace on this one, or NULL. + * Must be called with rcu_read_lock held to keep the returned struct alive. + * + * At exec time, this may be called with task_lock(p) still held from when + * tracehook_unsafe_exec was just called. In that case it must give + * results consistent with those unsafe_exec results, i.e. non-NULL if + * any LSM_UNSAFE_PTRACE_* bits were set. + * + * The value is also used to display after "TracerPid:" in /proc/PID/status, + * where it is called with only rcu_read_lock held. + */ +struct task_struct * +utrace_tracer_task(struct task_struct *target) +{ + struct utrace *utrace; + struct task_struct *tracer = NULL; + + utrace = rcu_dereference(target->utrace); + if (utrace != NULL) { + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + const struct utrace_engine_ops *ops; + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, + entry); + ops = rcu_dereference(engine->ops); + if (ops->tracer_task) { + tracer = (*ops->tracer_task)(engine, target); + if (tracer != NULL) + break; + } + } + } + + return tracer; +} + +int +utrace_allow_access_process_vm(struct task_struct *target) +{ + struct utrace *utrace; + int ret = 0; + + rcu_read_lock(); + utrace = rcu_dereference(target->utrace); + if (utrace != NULL) { + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + const struct utrace_engine_ops *ops; + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, + entry); + ops = rcu_dereference(engine->ops); + if (ops->allow_access_process_vm) { + ret = (*ops->allow_access_process_vm)(engine, + target, + current); + if (ret) + break; + } + } + } + rcu_read_unlock(); + + return ret; +} + +/* + * Called on the current task to return LSM_UNSAFE_* bits implied by tracing. + * Called with task_lock held. + */ +int +utrace_unsafe_exec(struct task_struct *tsk) +{ + struct utrace *utrace = tsk->utrace; + struct list_head *pos, *next; + struct utrace_attached_engine *engine; + const struct utrace_engine_ops *ops; + int unsafe = 0; + + /* XXX must change for sharing */ + list_for_each_safe_rcu(pos, next, &utrace->engines) { + engine = list_entry(pos, struct utrace_attached_engine, entry); + ops = rcu_dereference(engine->ops); + if (ops->unsafe_exec) + unsafe |= (*ops->unsafe_exec)(engine, tsk); + } + + return unsafe; +}