1*2d514487SKees Cook /* 2*2d514487SKees Cook * Yama Linux Security Module 3*2d514487SKees Cook * 4*2d514487SKees Cook * Author: Kees Cook <keescook@chromium.org> 5*2d514487SKees Cook * 6*2d514487SKees Cook * Copyright (C) 2010 Canonical, Ltd. 7*2d514487SKees Cook * Copyright (C) 2011 The Chromium OS Authors. 8*2d514487SKees Cook * 9*2d514487SKees Cook * This program is free software; you can redistribute it and/or modify 10*2d514487SKees Cook * it under the terms of the GNU General Public License version 2, as 11*2d514487SKees Cook * published by the Free Software Foundation. 12*2d514487SKees Cook * 13*2d514487SKees Cook */ 14*2d514487SKees Cook 15*2d514487SKees Cook #include <linux/security.h> 16*2d514487SKees Cook #include <linux/sysctl.h> 17*2d514487SKees Cook #include <linux/ptrace.h> 18*2d514487SKees Cook #include <linux/prctl.h> 19*2d514487SKees Cook #include <linux/ratelimit.h> 20*2d514487SKees Cook 21*2d514487SKees Cook static int ptrace_scope = 1; 22*2d514487SKees Cook 23*2d514487SKees Cook /* describe a ptrace relationship for potential exception */ 24*2d514487SKees Cook struct ptrace_relation { 25*2d514487SKees Cook struct task_struct *tracer; 26*2d514487SKees Cook struct task_struct *tracee; 27*2d514487SKees Cook struct list_head node; 28*2d514487SKees Cook }; 29*2d514487SKees Cook 30*2d514487SKees Cook static LIST_HEAD(ptracer_relations); 31*2d514487SKees Cook static DEFINE_SPINLOCK(ptracer_relations_lock); 32*2d514487SKees Cook 33*2d514487SKees Cook /** 34*2d514487SKees Cook * yama_ptracer_add - add/replace an exception for this tracer/tracee pair 35*2d514487SKees Cook * @tracer: the task_struct of the process doing the ptrace 36*2d514487SKees Cook * @tracee: the task_struct of the process to be ptraced 37*2d514487SKees Cook * 38*2d514487SKees Cook * Each tracee can have, at most, one tracer registered. Each time this 39*2d514487SKees Cook * is called, the prior registered tracer will be replaced for the tracee. 40*2d514487SKees Cook * 41*2d514487SKees Cook * Returns 0 if relationship was added, -ve on error. 42*2d514487SKees Cook */ 43*2d514487SKees Cook static int yama_ptracer_add(struct task_struct *tracer, 44*2d514487SKees Cook struct task_struct *tracee) 45*2d514487SKees Cook { 46*2d514487SKees Cook int rc = 0; 47*2d514487SKees Cook struct ptrace_relation *added; 48*2d514487SKees Cook struct ptrace_relation *entry, *relation = NULL; 49*2d514487SKees Cook 50*2d514487SKees Cook added = kmalloc(sizeof(*added), GFP_KERNEL); 51*2d514487SKees Cook if (!added) 52*2d514487SKees Cook return -ENOMEM; 53*2d514487SKees Cook 54*2d514487SKees Cook spin_lock_bh(&ptracer_relations_lock); 55*2d514487SKees Cook list_for_each_entry(entry, &ptracer_relations, node) 56*2d514487SKees Cook if (entry->tracee == tracee) { 57*2d514487SKees Cook relation = entry; 58*2d514487SKees Cook break; 59*2d514487SKees Cook } 60*2d514487SKees Cook if (!relation) { 61*2d514487SKees Cook relation = added; 62*2d514487SKees Cook relation->tracee = tracee; 63*2d514487SKees Cook list_add(&relation->node, &ptracer_relations); 64*2d514487SKees Cook } 65*2d514487SKees Cook relation->tracer = tracer; 66*2d514487SKees Cook 67*2d514487SKees Cook spin_unlock_bh(&ptracer_relations_lock); 68*2d514487SKees Cook if (added != relation) 69*2d514487SKees Cook kfree(added); 70*2d514487SKees Cook 71*2d514487SKees Cook return rc; 72*2d514487SKees Cook } 73*2d514487SKees Cook 74*2d514487SKees Cook /** 75*2d514487SKees Cook * yama_ptracer_del - remove exceptions related to the given tasks 76*2d514487SKees Cook * @tracer: remove any relation where tracer task matches 77*2d514487SKees Cook * @tracee: remove any relation where tracee task matches 78*2d514487SKees Cook */ 79*2d514487SKees Cook static void yama_ptracer_del(struct task_struct *tracer, 80*2d514487SKees Cook struct task_struct *tracee) 81*2d514487SKees Cook { 82*2d514487SKees Cook struct ptrace_relation *relation, *safe; 83*2d514487SKees Cook 84*2d514487SKees Cook spin_lock_bh(&ptracer_relations_lock); 85*2d514487SKees Cook list_for_each_entry_safe(relation, safe, &ptracer_relations, node) 86*2d514487SKees Cook if (relation->tracee == tracee || 87*2d514487SKees Cook relation->tracer == tracer) { 88*2d514487SKees Cook list_del(&relation->node); 89*2d514487SKees Cook kfree(relation); 90*2d514487SKees Cook } 91*2d514487SKees Cook spin_unlock_bh(&ptracer_relations_lock); 92*2d514487SKees Cook } 93*2d514487SKees Cook 94*2d514487SKees Cook /** 95*2d514487SKees Cook * yama_task_free - check for task_pid to remove from exception list 96*2d514487SKees Cook * @task: task being removed 97*2d514487SKees Cook */ 98*2d514487SKees Cook static void yama_task_free(struct task_struct *task) 99*2d514487SKees Cook { 100*2d514487SKees Cook yama_ptracer_del(task, task); 101*2d514487SKees Cook } 102*2d514487SKees Cook 103*2d514487SKees Cook /** 104*2d514487SKees Cook * yama_task_prctl - check for Yama-specific prctl operations 105*2d514487SKees Cook * @option: operation 106*2d514487SKees Cook * @arg2: argument 107*2d514487SKees Cook * @arg3: argument 108*2d514487SKees Cook * @arg4: argument 109*2d514487SKees Cook * @arg5: argument 110*2d514487SKees Cook * 111*2d514487SKees Cook * Return 0 on success, -ve on error. -ENOSYS is returned when Yama 112*2d514487SKees Cook * does not handle the given option. 113*2d514487SKees Cook */ 114*2d514487SKees Cook static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, 115*2d514487SKees Cook unsigned long arg4, unsigned long arg5) 116*2d514487SKees Cook { 117*2d514487SKees Cook int rc; 118*2d514487SKees Cook struct task_struct *myself = current; 119*2d514487SKees Cook 120*2d514487SKees Cook rc = cap_task_prctl(option, arg2, arg3, arg4, arg5); 121*2d514487SKees Cook if (rc != -ENOSYS) 122*2d514487SKees Cook return rc; 123*2d514487SKees Cook 124*2d514487SKees Cook switch (option) { 125*2d514487SKees Cook case PR_SET_PTRACER: 126*2d514487SKees Cook /* Since a thread can call prctl(), find the group leader 127*2d514487SKees Cook * before calling _add() or _del() on it, since we want 128*2d514487SKees Cook * process-level granularity of control. The tracer group 129*2d514487SKees Cook * leader checking is handled later when walking the ancestry 130*2d514487SKees Cook * at the time of PTRACE_ATTACH check. 131*2d514487SKees Cook */ 132*2d514487SKees Cook rcu_read_lock(); 133*2d514487SKees Cook if (!thread_group_leader(myself)) 134*2d514487SKees Cook myself = rcu_dereference(myself->group_leader); 135*2d514487SKees Cook get_task_struct(myself); 136*2d514487SKees Cook rcu_read_unlock(); 137*2d514487SKees Cook 138*2d514487SKees Cook if (arg2 == 0) { 139*2d514487SKees Cook yama_ptracer_del(NULL, myself); 140*2d514487SKees Cook rc = 0; 141*2d514487SKees Cook } else { 142*2d514487SKees Cook struct task_struct *tracer; 143*2d514487SKees Cook 144*2d514487SKees Cook rcu_read_lock(); 145*2d514487SKees Cook tracer = find_task_by_vpid(arg2); 146*2d514487SKees Cook if (tracer) 147*2d514487SKees Cook get_task_struct(tracer); 148*2d514487SKees Cook else 149*2d514487SKees Cook rc = -EINVAL; 150*2d514487SKees Cook rcu_read_unlock(); 151*2d514487SKees Cook 152*2d514487SKees Cook if (tracer) { 153*2d514487SKees Cook rc = yama_ptracer_add(tracer, myself); 154*2d514487SKees Cook put_task_struct(tracer); 155*2d514487SKees Cook } 156*2d514487SKees Cook } 157*2d514487SKees Cook 158*2d514487SKees Cook put_task_struct(myself); 159*2d514487SKees Cook break; 160*2d514487SKees Cook } 161*2d514487SKees Cook 162*2d514487SKees Cook return rc; 163*2d514487SKees Cook } 164*2d514487SKees Cook 165*2d514487SKees Cook /** 166*2d514487SKees Cook * task_is_descendant - walk up a process family tree looking for a match 167*2d514487SKees Cook * @parent: the process to compare against while walking up from child 168*2d514487SKees Cook * @child: the process to start from while looking upwards for parent 169*2d514487SKees Cook * 170*2d514487SKees Cook * Returns 1 if child is a descendant of parent, 0 if not. 171*2d514487SKees Cook */ 172*2d514487SKees Cook static int task_is_descendant(struct task_struct *parent, 173*2d514487SKees Cook struct task_struct *child) 174*2d514487SKees Cook { 175*2d514487SKees Cook int rc = 0; 176*2d514487SKees Cook struct task_struct *walker = child; 177*2d514487SKees Cook 178*2d514487SKees Cook if (!parent || !child) 179*2d514487SKees Cook return 0; 180*2d514487SKees Cook 181*2d514487SKees Cook rcu_read_lock(); 182*2d514487SKees Cook if (!thread_group_leader(parent)) 183*2d514487SKees Cook parent = rcu_dereference(parent->group_leader); 184*2d514487SKees Cook while (walker->pid > 0) { 185*2d514487SKees Cook if (!thread_group_leader(walker)) 186*2d514487SKees Cook walker = rcu_dereference(walker->group_leader); 187*2d514487SKees Cook if (walker == parent) { 188*2d514487SKees Cook rc = 1; 189*2d514487SKees Cook break; 190*2d514487SKees Cook } 191*2d514487SKees Cook walker = rcu_dereference(walker->real_parent); 192*2d514487SKees Cook } 193*2d514487SKees Cook rcu_read_unlock(); 194*2d514487SKees Cook 195*2d514487SKees Cook return rc; 196*2d514487SKees Cook } 197*2d514487SKees Cook 198*2d514487SKees Cook /** 199*2d514487SKees Cook * ptracer_exception_found - tracer registered as exception for this tracee 200*2d514487SKees Cook * @tracer: the task_struct of the process attempting ptrace 201*2d514487SKees Cook * @tracee: the task_struct of the process to be ptraced 202*2d514487SKees Cook * 203*2d514487SKees Cook * Returns 1 if tracer has is ptracer exception ancestor for tracee. 204*2d514487SKees Cook */ 205*2d514487SKees Cook static int ptracer_exception_found(struct task_struct *tracer, 206*2d514487SKees Cook struct task_struct *tracee) 207*2d514487SKees Cook { 208*2d514487SKees Cook int rc = 0; 209*2d514487SKees Cook struct ptrace_relation *relation; 210*2d514487SKees Cook struct task_struct *parent = NULL; 211*2d514487SKees Cook 212*2d514487SKees Cook spin_lock_bh(&ptracer_relations_lock); 213*2d514487SKees Cook rcu_read_lock(); 214*2d514487SKees Cook if (!thread_group_leader(tracee)) 215*2d514487SKees Cook tracee = rcu_dereference(tracee->group_leader); 216*2d514487SKees Cook list_for_each_entry(relation, &ptracer_relations, node) 217*2d514487SKees Cook if (relation->tracee == tracee) { 218*2d514487SKees Cook parent = relation->tracer; 219*2d514487SKees Cook break; 220*2d514487SKees Cook } 221*2d514487SKees Cook 222*2d514487SKees Cook if (task_is_descendant(parent, tracer)) 223*2d514487SKees Cook rc = 1; 224*2d514487SKees Cook rcu_read_unlock(); 225*2d514487SKees Cook spin_unlock_bh(&ptracer_relations_lock); 226*2d514487SKees Cook 227*2d514487SKees Cook return rc; 228*2d514487SKees Cook } 229*2d514487SKees Cook 230*2d514487SKees Cook /** 231*2d514487SKees Cook * yama_ptrace_access_check - validate PTRACE_ATTACH calls 232*2d514487SKees Cook * @child: task that current task is attempting to ptrace 233*2d514487SKees Cook * @mode: ptrace attach mode 234*2d514487SKees Cook * 235*2d514487SKees Cook * Returns 0 if following the ptrace is allowed, -ve on error. 236*2d514487SKees Cook */ 237*2d514487SKees Cook static int yama_ptrace_access_check(struct task_struct *child, 238*2d514487SKees Cook unsigned int mode) 239*2d514487SKees Cook { 240*2d514487SKees Cook int rc; 241*2d514487SKees Cook 242*2d514487SKees Cook /* If standard caps disallows it, so does Yama. We should 243*2d514487SKees Cook * only tighten restrictions further. 244*2d514487SKees Cook */ 245*2d514487SKees Cook rc = cap_ptrace_access_check(child, mode); 246*2d514487SKees Cook if (rc) 247*2d514487SKees Cook return rc; 248*2d514487SKees Cook 249*2d514487SKees Cook /* require ptrace target be a child of ptracer on attach */ 250*2d514487SKees Cook if (mode == PTRACE_MODE_ATTACH && 251*2d514487SKees Cook ptrace_scope && 252*2d514487SKees Cook !task_is_descendant(current, child) && 253*2d514487SKees Cook !ptracer_exception_found(current, child) && 254*2d514487SKees Cook !capable(CAP_SYS_PTRACE)) 255*2d514487SKees Cook rc = -EPERM; 256*2d514487SKees Cook 257*2d514487SKees Cook if (rc) { 258*2d514487SKees Cook char name[sizeof(current->comm)]; 259*2d514487SKees Cook printk_ratelimited(KERN_NOTICE "ptrace of non-child" 260*2d514487SKees Cook " pid %d was attempted by: %s (pid %d)\n", 261*2d514487SKees Cook child->pid, 262*2d514487SKees Cook get_task_comm(name, current), 263*2d514487SKees Cook current->pid); 264*2d514487SKees Cook } 265*2d514487SKees Cook 266*2d514487SKees Cook return rc; 267*2d514487SKees Cook } 268*2d514487SKees Cook 269*2d514487SKees Cook static struct security_operations yama_ops = { 270*2d514487SKees Cook .name = "yama", 271*2d514487SKees Cook 272*2d514487SKees Cook .ptrace_access_check = yama_ptrace_access_check, 273*2d514487SKees Cook .task_prctl = yama_task_prctl, 274*2d514487SKees Cook .task_free = yama_task_free, 275*2d514487SKees Cook }; 276*2d514487SKees Cook 277*2d514487SKees Cook #ifdef CONFIG_SYSCTL 278*2d514487SKees Cook static int zero; 279*2d514487SKees Cook static int one = 1; 280*2d514487SKees Cook 281*2d514487SKees Cook struct ctl_path yama_sysctl_path[] = { 282*2d514487SKees Cook { .procname = "kernel", }, 283*2d514487SKees Cook { .procname = "yama", }, 284*2d514487SKees Cook { } 285*2d514487SKees Cook }; 286*2d514487SKees Cook 287*2d514487SKees Cook static struct ctl_table yama_sysctl_table[] = { 288*2d514487SKees Cook { 289*2d514487SKees Cook .procname = "ptrace_scope", 290*2d514487SKees Cook .data = &ptrace_scope, 291*2d514487SKees Cook .maxlen = sizeof(int), 292*2d514487SKees Cook .mode = 0644, 293*2d514487SKees Cook .proc_handler = proc_dointvec_minmax, 294*2d514487SKees Cook .extra1 = &zero, 295*2d514487SKees Cook .extra2 = &one, 296*2d514487SKees Cook }, 297*2d514487SKees Cook { } 298*2d514487SKees Cook }; 299*2d514487SKees Cook #endif /* CONFIG_SYSCTL */ 300*2d514487SKees Cook 301*2d514487SKees Cook static __init int yama_init(void) 302*2d514487SKees Cook { 303*2d514487SKees Cook if (!security_module_enable(&yama_ops)) 304*2d514487SKees Cook return 0; 305*2d514487SKees Cook 306*2d514487SKees Cook printk(KERN_INFO "Yama: becoming mindful.\n"); 307*2d514487SKees Cook 308*2d514487SKees Cook if (register_security(&yama_ops)) 309*2d514487SKees Cook panic("Yama: kernel registration failed.\n"); 310*2d514487SKees Cook 311*2d514487SKees Cook #ifdef CONFIG_SYSCTL 312*2d514487SKees Cook if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) 313*2d514487SKees Cook panic("Yama: sysctl registration failed.\n"); 314*2d514487SKees Cook #endif 315*2d514487SKees Cook 316*2d514487SKees Cook return 0; 317*2d514487SKees Cook } 318*2d514487SKees Cook 319*2d514487SKees Cook security_initcall(yama_init); 320