Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

security: Yama LSM

This adds the Yama Linux Security Module to collect DAC security
improvements (specifically just ptrace restrictions for now) that have
existed in various forms over the years and have been carried outside the
mainline kernel by other Linux distributions like Openwall and grsecurity.

Signed-off-by: Kees Cook <keescook@chromium.org>
Acked-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: James Morris <jmorris@namei.org>

authored by

Kees Cook and committed by
James Morris
2d514487 1a2a4d06

+411
+2
Documentation/security/00-INDEX
··· 6 6 - how to get started with the SELinux security enhancement. 7 7 Smack.txt 8 8 - documentation on the Smack Linux Security Module. 9 + Yama.txt 10 + - documentation on the Yama Linux Security Module. 9 11 apparmor.txt 10 12 - documentation on the AppArmor security extension. 11 13 credentials.txt
+60
Documentation/security/Yama.txt
··· 1 + Yama is a Linux Security Module that collects a number of system-wide DAC 2 + security protections that are not handled by the core kernel itself. To 3 + select it at boot time, specify "security=yama" (though this will disable 4 + any other LSM). 5 + 6 + Yama is controlled through sysctl in /proc/sys/kernel/yama: 7 + 8 + - ptrace_scope 9 + 10 + ============================================================== 11 + 12 + ptrace_scope: 13 + 14 + As Linux grows in popularity, it will become a larger target for 15 + malware. One particularly troubling weakness of the Linux process 16 + interfaces is that a single user is able to examine the memory and 17 + running state of any of their processes. For example, if one application 18 + (e.g. Pidgin) was compromised, it would be possible for an attacker to 19 + attach to other running processes (e.g. Firefox, SSH sessions, GPG agent, 20 + etc) to extract additional credentials and continue to expand the scope 21 + of their attack without resorting to user-assisted phishing. 22 + 23 + This is not a theoretical problem. SSH session hijacking 24 + (http://www.storm.net.nz/projects/7) and arbitrary code injection 25 + (http://c-skills.blogspot.com/2007/05/injectso.html) attacks already 26 + exist and remain possible if ptrace is allowed to operate as before. 27 + Since ptrace is not commonly used by non-developers and non-admins, system 28 + builders should be allowed the option to disable this debugging system. 29 + 30 + For a solution, some applications use prctl(PR_SET_DUMPABLE, ...) to 31 + specifically disallow such ptrace attachment (e.g. ssh-agent), but many 32 + do not. A more general solution is to only allow ptrace directly from a 33 + parent to a child process (i.e. direct "gdb EXE" and "strace EXE" still 34 + work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID" 35 + still work as root). 36 + 37 + For software that has defined application-specific relationships 38 + between a debugging process and its inferior (crash handlers, etc), 39 + prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which 40 + other process (and its descendents) are allowed to call PTRACE_ATTACH 41 + against it. Only one such declared debugging process can exists for 42 + each inferior at a time. For example, this is used by KDE, Chromium, and 43 + Firefox's crash handlers, and by Wine for allowing only Wine processes 44 + to ptrace each other. 45 + 46 + 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other 47 + process running under the same uid, as long as it is dumpable (i.e. 48 + did not transition uids, start privileged, or have called 49 + prctl(PR_SET_DUMPABLE...) already). 50 + 51 + 1 - restricted ptrace: a process must have a predefined relationship 52 + with the inferior it wants to call PTRACE_ATTACH on. By default, 53 + this relationship is that of only its descendants when the above 54 + classic criteria is also met. To change the relationship, an 55 + inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare 56 + an allowed debugger PID to call PTRACE_ATTACH on the inferior. 57 + 58 + The original children-only logic was based on the restrictions in grsecurity. 59 + 60 + ==============================================================
+6
include/linux/prctl.h
··· 114 114 # define PR_SET_MM_START_BRK 6 115 115 # define PR_SET_MM_BRK 7 116 116 117 + /* 118 + * Set specific pid that is allowed to ptrace the current task. 119 + * A value of 0 mean "no process". 120 + */ 121 + #define PR_SET_PTRACER 0x59616d61 122 + 117 123 #endif /* _LINUX_PRCTL_H */
+6
security/Kconfig
··· 187 187 source security/smack/Kconfig 188 188 source security/tomoyo/Kconfig 189 189 source security/apparmor/Kconfig 190 + source security/yama/Kconfig 190 191 191 192 source security/integrity/Kconfig 192 193 ··· 197 196 default DEFAULT_SECURITY_SMACK if SECURITY_SMACK 198 197 default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO 199 198 default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR 199 + default DEFAULT_SECURITY_YAMA if SECURITY_YAMA 200 200 default DEFAULT_SECURITY_DAC 201 201 202 202 help ··· 216 214 config DEFAULT_SECURITY_APPARMOR 217 215 bool "AppArmor" if SECURITY_APPARMOR=y 218 216 217 + config DEFAULT_SECURITY_YAMA 218 + bool "Yama" if SECURITY_YAMA=y 219 + 219 220 config DEFAULT_SECURITY_DAC 220 221 bool "Unix Discretionary Access Controls" 221 222 ··· 230 225 default "smack" if DEFAULT_SECURITY_SMACK 231 226 default "tomoyo" if DEFAULT_SECURITY_TOMOYO 232 227 default "apparmor" if DEFAULT_SECURITY_APPARMOR 228 + default "yama" if DEFAULT_SECURITY_YAMA 233 229 default "" if DEFAULT_SECURITY_DAC 234 230 235 231 endmenu
+2
security/Makefile
··· 7 7 subdir-$(CONFIG_SECURITY_SMACK) += smack 8 8 subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo 9 9 subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor 10 + subdir-$(CONFIG_SECURITY_YAMA) += yama 10 11 11 12 # always enable default capabilities 12 13 obj-y += commoncap.o ··· 22 21 obj-$(CONFIG_AUDIT) += lsm_audit.o 23 22 obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o 24 23 obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o 24 + obj-$(CONFIG_SECURITY_YAMA) += yama/built-in.o 25 25 obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o 26 26 27 27 # Object integrity file lists
+13
security/yama/Kconfig
··· 1 + config SECURITY_YAMA 2 + bool "Yama support" 3 + depends on SECURITY 4 + select SECURITYFS 5 + select SECURITY_PATH 6 + default n 7 + help 8 + This selects Yama, which extends DAC support with additional 9 + system-wide security settings beyond regular Linux discretionary 10 + access controls. Currently available is ptrace scope restriction. 11 + Further information can be found in Documentation/security/Yama.txt. 12 + 13 + If you are unsure how to answer this question, answer N.
+3
security/yama/Makefile
··· 1 + obj-$(CONFIG_SECURITY_YAMA) := yama.o 2 + 3 + yama-y := yama_lsm.o
+319
security/yama/yama_lsm.c
··· 1 + /* 2 + * Yama Linux Security Module 3 + * 4 + * Author: Kees Cook <keescook@chromium.org> 5 + * 6 + * Copyright (C) 2010 Canonical, Ltd. 7 + * Copyright (C) 2011 The Chromium OS Authors. 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License version 2, as 11 + * published by the Free Software Foundation. 12 + * 13 + */ 14 + 15 + #include <linux/security.h> 16 + #include <linux/sysctl.h> 17 + #include <linux/ptrace.h> 18 + #include <linux/prctl.h> 19 + #include <linux/ratelimit.h> 20 + 21 + static int ptrace_scope = 1; 22 + 23 + /* describe a ptrace relationship for potential exception */ 24 + struct ptrace_relation { 25 + struct task_struct *tracer; 26 + struct task_struct *tracee; 27 + struct list_head node; 28 + }; 29 + 30 + static LIST_HEAD(ptracer_relations); 31 + static DEFINE_SPINLOCK(ptracer_relations_lock); 32 + 33 + /** 34 + * yama_ptracer_add - add/replace an exception for this tracer/tracee pair 35 + * @tracer: the task_struct of the process doing the ptrace 36 + * @tracee: the task_struct of the process to be ptraced 37 + * 38 + * Each tracee can have, at most, one tracer registered. Each time this 39 + * is called, the prior registered tracer will be replaced for the tracee. 40 + * 41 + * Returns 0 if relationship was added, -ve on error. 42 + */ 43 + static int yama_ptracer_add(struct task_struct *tracer, 44 + struct task_struct *tracee) 45 + { 46 + int rc = 0; 47 + struct ptrace_relation *added; 48 + struct ptrace_relation *entry, *relation = NULL; 49 + 50 + added = kmalloc(sizeof(*added), GFP_KERNEL); 51 + if (!added) 52 + return -ENOMEM; 53 + 54 + spin_lock_bh(&ptracer_relations_lock); 55 + list_for_each_entry(entry, &ptracer_relations, node) 56 + if (entry->tracee == tracee) { 57 + relation = entry; 58 + break; 59 + } 60 + if (!relation) { 61 + relation = added; 62 + relation->tracee = tracee; 63 + list_add(&relation->node, &ptracer_relations); 64 + } 65 + relation->tracer = tracer; 66 + 67 + spin_unlock_bh(&ptracer_relations_lock); 68 + if (added != relation) 69 + kfree(added); 70 + 71 + return rc; 72 + } 73 + 74 + /** 75 + * yama_ptracer_del - remove exceptions related to the given tasks 76 + * @tracer: remove any relation where tracer task matches 77 + * @tracee: remove any relation where tracee task matches 78 + */ 79 + static void yama_ptracer_del(struct task_struct *tracer, 80 + struct task_struct *tracee) 81 + { 82 + struct ptrace_relation *relation, *safe; 83 + 84 + spin_lock_bh(&ptracer_relations_lock); 85 + list_for_each_entry_safe(relation, safe, &ptracer_relations, node) 86 + if (relation->tracee == tracee || 87 + relation->tracer == tracer) { 88 + list_del(&relation->node); 89 + kfree(relation); 90 + } 91 + spin_unlock_bh(&ptracer_relations_lock); 92 + } 93 + 94 + /** 95 + * yama_task_free - check for task_pid to remove from exception list 96 + * @task: task being removed 97 + */ 98 + static void yama_task_free(struct task_struct *task) 99 + { 100 + yama_ptracer_del(task, task); 101 + } 102 + 103 + /** 104 + * yama_task_prctl - check for Yama-specific prctl operations 105 + * @option: operation 106 + * @arg2: argument 107 + * @arg3: argument 108 + * @arg4: argument 109 + * @arg5: argument 110 + * 111 + * Return 0 on success, -ve on error. -ENOSYS is returned when Yama 112 + * does not handle the given option. 113 + */ 114 + static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, 115 + unsigned long arg4, unsigned long arg5) 116 + { 117 + int rc; 118 + struct task_struct *myself = current; 119 + 120 + rc = cap_task_prctl(option, arg2, arg3, arg4, arg5); 121 + if (rc != -ENOSYS) 122 + return rc; 123 + 124 + switch (option) { 125 + case PR_SET_PTRACER: 126 + /* Since a thread can call prctl(), find the group leader 127 + * before calling _add() or _del() on it, since we want 128 + * process-level granularity of control. The tracer group 129 + * leader checking is handled later when walking the ancestry 130 + * at the time of PTRACE_ATTACH check. 131 + */ 132 + rcu_read_lock(); 133 + if (!thread_group_leader(myself)) 134 + myself = rcu_dereference(myself->group_leader); 135 + get_task_struct(myself); 136 + rcu_read_unlock(); 137 + 138 + if (arg2 == 0) { 139 + yama_ptracer_del(NULL, myself); 140 + rc = 0; 141 + } else { 142 + struct task_struct *tracer; 143 + 144 + rcu_read_lock(); 145 + tracer = find_task_by_vpid(arg2); 146 + if (tracer) 147 + get_task_struct(tracer); 148 + else 149 + rc = -EINVAL; 150 + rcu_read_unlock(); 151 + 152 + if (tracer) { 153 + rc = yama_ptracer_add(tracer, myself); 154 + put_task_struct(tracer); 155 + } 156 + } 157 + 158 + put_task_struct(myself); 159 + break; 160 + } 161 + 162 + return rc; 163 + } 164 + 165 + /** 166 + * task_is_descendant - walk up a process family tree looking for a match 167 + * @parent: the process to compare against while walking up from child 168 + * @child: the process to start from while looking upwards for parent 169 + * 170 + * Returns 1 if child is a descendant of parent, 0 if not. 171 + */ 172 + static int task_is_descendant(struct task_struct *parent, 173 + struct task_struct *child) 174 + { 175 + int rc = 0; 176 + struct task_struct *walker = child; 177 + 178 + if (!parent || !child) 179 + return 0; 180 + 181 + rcu_read_lock(); 182 + if (!thread_group_leader(parent)) 183 + parent = rcu_dereference(parent->group_leader); 184 + while (walker->pid > 0) { 185 + if (!thread_group_leader(walker)) 186 + walker = rcu_dereference(walker->group_leader); 187 + if (walker == parent) { 188 + rc = 1; 189 + break; 190 + } 191 + walker = rcu_dereference(walker->real_parent); 192 + } 193 + rcu_read_unlock(); 194 + 195 + return rc; 196 + } 197 + 198 + /** 199 + * ptracer_exception_found - tracer registered as exception for this tracee 200 + * @tracer: the task_struct of the process attempting ptrace 201 + * @tracee: the task_struct of the process to be ptraced 202 + * 203 + * Returns 1 if tracer has is ptracer exception ancestor for tracee. 204 + */ 205 + static int ptracer_exception_found(struct task_struct *tracer, 206 + struct task_struct *tracee) 207 + { 208 + int rc = 0; 209 + struct ptrace_relation *relation; 210 + struct task_struct *parent = NULL; 211 + 212 + spin_lock_bh(&ptracer_relations_lock); 213 + rcu_read_lock(); 214 + if (!thread_group_leader(tracee)) 215 + tracee = rcu_dereference(tracee->group_leader); 216 + list_for_each_entry(relation, &ptracer_relations, node) 217 + if (relation->tracee == tracee) { 218 + parent = relation->tracer; 219 + break; 220 + } 221 + 222 + if (task_is_descendant(parent, tracer)) 223 + rc = 1; 224 + rcu_read_unlock(); 225 + spin_unlock_bh(&ptracer_relations_lock); 226 + 227 + return rc; 228 + } 229 + 230 + /** 231 + * yama_ptrace_access_check - validate PTRACE_ATTACH calls 232 + * @child: task that current task is attempting to ptrace 233 + * @mode: ptrace attach mode 234 + * 235 + * Returns 0 if following the ptrace is allowed, -ve on error. 236 + */ 237 + static int yama_ptrace_access_check(struct task_struct *child, 238 + unsigned int mode) 239 + { 240 + int rc; 241 + 242 + /* If standard caps disallows it, so does Yama. We should 243 + * only tighten restrictions further. 244 + */ 245 + rc = cap_ptrace_access_check(child, mode); 246 + if (rc) 247 + return rc; 248 + 249 + /* require ptrace target be a child of ptracer on attach */ 250 + if (mode == PTRACE_MODE_ATTACH && 251 + ptrace_scope && 252 + !task_is_descendant(current, child) && 253 + !ptracer_exception_found(current, child) && 254 + !capable(CAP_SYS_PTRACE)) 255 + rc = -EPERM; 256 + 257 + if (rc) { 258 + char name[sizeof(current->comm)]; 259 + printk_ratelimited(KERN_NOTICE "ptrace of non-child" 260 + " pid %d was attempted by: %s (pid %d)\n", 261 + child->pid, 262 + get_task_comm(name, current), 263 + current->pid); 264 + } 265 + 266 + return rc; 267 + } 268 + 269 + static struct security_operations yama_ops = { 270 + .name = "yama", 271 + 272 + .ptrace_access_check = yama_ptrace_access_check, 273 + .task_prctl = yama_task_prctl, 274 + .task_free = yama_task_free, 275 + }; 276 + 277 + #ifdef CONFIG_SYSCTL 278 + static int zero; 279 + static int one = 1; 280 + 281 + struct ctl_path yama_sysctl_path[] = { 282 + { .procname = "kernel", }, 283 + { .procname = "yama", }, 284 + { } 285 + }; 286 + 287 + static struct ctl_table yama_sysctl_table[] = { 288 + { 289 + .procname = "ptrace_scope", 290 + .data = &ptrace_scope, 291 + .maxlen = sizeof(int), 292 + .mode = 0644, 293 + .proc_handler = proc_dointvec_minmax, 294 + .extra1 = &zero, 295 + .extra2 = &one, 296 + }, 297 + { } 298 + }; 299 + #endif /* CONFIG_SYSCTL */ 300 + 301 + static __init int yama_init(void) 302 + { 303 + if (!security_module_enable(&yama_ops)) 304 + return 0; 305 + 306 + printk(KERN_INFO "Yama: becoming mindful.\n"); 307 + 308 + if (register_security(&yama_ops)) 309 + panic("Yama: kernel registration failed.\n"); 310 + 311 + #ifdef CONFIG_SYSCTL 312 + if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) 313 + panic("Yama: sysctl registration failed.\n"); 314 + #endif 315 + 316 + return 0; 317 + } 318 + 319 + security_initcall(yama_init);