diff options
Diffstat (limited to 'security/yama')
-rw-r--r-- | security/yama/yama_lsm.c | 84 |
1 files changed, 76 insertions, 8 deletions
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index cb6ed1081..0309f2111 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -18,6 +18,10 @@ #include <linux/prctl.h> #include <linux/ratelimit.h> #include <linux/workqueue.h> +#include <linux/string_helpers.h> +#include <linux/task_work.h> +#include <linux/sched.h> +#include <linux/spinlock.h> #define YAMA_SCOPE_DISABLED 0 #define YAMA_SCOPE_RELATIONAL 1 @@ -41,6 +45,73 @@ static DEFINE_SPINLOCK(ptracer_relations_lock); static void yama_relation_cleanup(struct work_struct *work); static DECLARE_WORK(yama_relation_work, yama_relation_cleanup); +struct access_report_info { + struct callback_head work; + const char *access; + struct task_struct *target; + struct task_struct *agent; +}; + +static void __report_access(struct callback_head *work) +{ + struct access_report_info *info = + container_of(work, struct access_report_info, work); + char *target_cmd, *agent_cmd; + + target_cmd = kstrdup_quotable_cmdline(info->target, GFP_KERNEL); + agent_cmd = kstrdup_quotable_cmdline(info->agent, GFP_KERNEL); + + pr_notice_ratelimited( + "ptrace %s of \"%s\"[%d] was attempted by \"%s\"[%d]\n", + info->access, target_cmd, info->target->pid, agent_cmd, + info->agent->pid); + + kfree(agent_cmd); + kfree(target_cmd); + + put_task_struct(info->agent); + put_task_struct(info->target); + kfree(info); +} + +/* defers execution because cmdline access can sleep */ +static void report_access(const char *access, struct task_struct *target, + struct task_struct *agent) +{ + struct access_report_info *info; + char agent_comm[sizeof(agent->comm)]; + + assert_spin_locked(&target->alloc_lock); /* for target->comm */ + + if (current->flags & PF_KTHREAD) { + /* I don't think kthreads call task_work_run() before exiting. + * Imagine angry ranting about procfs here. + */ + pr_notice_ratelimited( + "ptrace %s of \"%s\"[%d] was attempted by \"%s\"[%d]\n", + access, target->comm, target->pid, + get_task_comm(agent_comm, agent), agent->pid); + return; + } + + info = kmalloc(sizeof(*info), GFP_ATOMIC); + if (!info) + return; + init_task_work(&info->work, __report_access); + get_task_struct(target); + get_task_struct(agent); + info->access = access; + info->target = target; + info->agent = agent; + if (task_work_add(current, &info->work, true) == 0) + return; /* success */ + + WARN(1, "report_access called from exiting task"); + put_task_struct(target); + put_task_struct(agent); + kfree(info); +} + /** * yama_relation_cleanup - remove invalid entries from the relation list * @@ -307,11 +378,8 @@ static int yama_ptrace_access_check(struct task_struct *child, } } - if (rc && (mode & PTRACE_MODE_NOAUDIT) == 0) { - printk_ratelimited(KERN_NOTICE - "ptrace of pid %d was attempted by: %s (pid %d)\n", - child->pid, current->comm, current->pid); - } + if (rc && (mode & PTRACE_MODE_NOAUDIT) == 0) + report_access("attach", child, current); return rc; } @@ -338,9 +406,9 @@ int yama_ptrace_traceme(struct task_struct *parent) } if (rc) { - printk_ratelimited(KERN_NOTICE - "ptraceme of pid %d was attempted by: %s (pid %d)\n", - current->pid, parent->comm, parent->pid); + task_lock(current); + report_access("traceme", current, parent); + task_unlock(current); } return rc; |