OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Yama Linux Security Module |
| 3 * |
| 4 * Author: Kees Cook <kees.cook@canonical.com> |
| 5 * |
| 6 * Copyright (C) 2010 Canonical, Ltd. |
| 7 * |
| 8 * This program is free software; you can redistribute it and/or modify |
| 9 * it under the terms of the GNU General Public License version 2, as |
| 10 * published by the Free Software Foundation. |
| 11 * |
| 12 */ |
| 13 |
| 14 #include <linux/security.h> |
| 15 #include <linux/sysctl.h> |
| 16 #include <linux/ptrace.h> |
| 17 #include <linux/ratelimit.h> |
| 18 |
| 19 /* Ratelimiting from the future. */ |
| 20 #ifndef printk_ratelimited |
| 21 #ifdef CONFIG_PRINTK |
| 22 #define printk_ratelimited(fmt, ...) ({ \ |
| 23 static DEFINE_RATELIMIT_STATE(_rs, \ |
| 24 DEFAULT_RATELIMIT_INTERVAL, \ |
| 25 DEFAULT_RATELIMIT_BURST); \ |
| 26 \ |
| 27 if (__ratelimit(&_rs)) \ |
| 28 printk(fmt, ##__VA_ARGS__); \ |
| 29 }) |
| 30 #else |
| 31 /* No effect, but we still get type checking even in the !PRINTK case: */ |
| 32 #define printk_ratelimited printk |
| 33 #endif |
| 34 #endif |
| 35 |
| 36 static int ptrace_scope = 1; |
| 37 static int protected_sticky_symlinks = 1; |
| 38 static int protected_nonaccess_hardlinks = 1; |
| 39 |
| 40 /** |
| 41 * yama_ptrace_access_check - validate PTRACE_ATTACH calls |
| 42 * @child: child task pointer |
| 43 * @mode: ptrace attach mode |
| 44 * |
| 45 * Returns 0 if following the ptrace is allowed, -ve on error. |
| 46 */ |
| 47 static int yama_ptrace_access_check(struct task_struct *child, |
| 48 unsigned int mode) |
| 49 { |
| 50 int rc; |
| 51 |
| 52 rc = cap_ptrace_access_check(child, mode); |
| 53 if (rc != 0) |
| 54 return rc; |
| 55 |
| 56 /* require ptrace target be a child of ptracer on attach */ |
| 57 if (mode == PTRACE_MODE_ATTACH && ptrace_scope && |
| 58 !capable(CAP_SYS_PTRACE)) { |
| 59 struct task_struct *walker = child; |
| 60 |
| 61 rcu_read_lock(); |
| 62 read_lock(&tasklist_lock); |
| 63 while (walker->pid > 0) { |
| 64 if (walker == current) |
| 65 break; |
| 66 walker = walker->real_parent; |
| 67 } |
| 68 if (walker->pid == 0) |
| 69 rc = -EPERM; |
| 70 read_unlock(&tasklist_lock); |
| 71 rcu_read_unlock(); |
| 72 } |
| 73 |
| 74 if (rc) { |
| 75 char name[sizeof(current->comm)]; |
| 76 printk_ratelimited(KERN_INFO "ptrace of non-child" |
| 77 " pid %d was attempted by: %s (pid %d)\n", |
| 78 child->pid, |
| 79 get_task_comm(name, current), |
| 80 current->pid); |
| 81 } |
| 82 |
| 83 return rc; |
| 84 } |
| 85 |
| 86 /** |
| 87 * yama_inode_follow_link - check for symlinks in sticky world-writeable dirs |
| 88 * @dentry: The inode/dentry of the symlink |
| 89 * @nameidata: The path data of the symlink |
| 90 * |
| 91 * In the case of the protected_sticky_symlinks sysctl being enabled, |
| 92 * CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is |
| 93 * in a sticky world-writable directory. This is to protect privileged |
| 94 * processes from failing races against path names that may change out |
| 95 * from under them by way of other users creating malicious symlinks. |
| 96 * It will permit symlinks to only be followed when outside a sticky |
| 97 * world-writable directory, or when the uid of the symlink and follower |
| 98 * match, or when the directory owner matches the symlink's owner. |
| 99 * |
| 100 * Returns 0 if following the symlink is allowed, -ve on error. |
| 101 */ |
| 102 static int yama_inode_follow_link(struct dentry *dentry, |
| 103 struct nameidata *nameidata) |
| 104 { |
| 105 int rc = 0; |
| 106 const struct inode *parent; |
| 107 const struct inode *inode; |
| 108 const struct cred *cred; |
| 109 |
| 110 if (!protected_sticky_symlinks) |
| 111 return 0; |
| 112 |
| 113 /* owner and follower match? */ |
| 114 cred = current_cred(); |
| 115 inode = dentry->d_inode; |
| 116 if (cred->fsuid == inode->i_uid) |
| 117 return 0; |
| 118 |
| 119 /* check parent directory mode and owner */ |
| 120 spin_lock(&dentry->d_lock); |
| 121 parent = dentry->d_parent->d_inode; |
| 122 if ((parent->i_mode & (S_ISVTX|S_IWOTH)) == (S_ISVTX|S_IWOTH) && |
| 123 parent->i_uid != inode->i_uid) { |
| 124 rc = -EACCES; |
| 125 } |
| 126 spin_unlock(&dentry->d_lock); |
| 127 |
| 128 if (rc) { |
| 129 char name[sizeof(current->comm)]; |
| 130 printk_ratelimited(KERN_NOTICE "non-matching-uid symlink " |
| 131 "following attempted in sticky world-writable " |
| 132 "directory by %s (fsuid %d != %d)\n", |
| 133 get_task_comm(name, current), |
| 134 cred->fsuid, inode->i_uid); |
| 135 } |
| 136 |
| 137 return rc; |
| 138 } |
| 139 |
| 140 /** |
| 141 * yama_path_link - verify that hardlinking is allowed |
| 142 * @old_dentry: the source inode/dentry to hardlink from |
| 143 * @new_dir: target directory |
| 144 * @new_dentry: the target inode/dentry to hardlink to |
| 145 * |
| 146 * Block hardlink when all of: |
| 147 * - fsuid does not match inode |
| 148 * - not CAP_FOWNER |
| 149 * - and at least one of: |
| 150 * - inode is not a regular file |
| 151 * - inode is setuid |
| 152 * - inode is setgid and group-exec |
| 153 * - access failure for read and write |
| 154 * |
| 155 * Returns 0 if successful, -ve on error. |
| 156 */ |
| 157 static int yama_path_link(struct dentry *old_dentry, struct path *new_dir, |
| 158 struct dentry *new_dentry) |
| 159 { |
| 160 int rc = 0; |
| 161 struct inode *inode = old_dentry->d_inode; |
| 162 const int mode = inode->i_mode; |
| 163 const struct cred *cred = current_cred(); |
| 164 |
| 165 if (!protected_nonaccess_hardlinks) |
| 166 return 0; |
| 167 |
| 168 if (cred->fsuid != inode->i_uid && |
| 169 (!S_ISREG(mode) || (mode & S_ISUID) || |
| 170 ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) || |
| 171 (generic_permission(inode, MAY_READ | MAY_WRITE, NULL))) && |
| 172 !capable(CAP_FOWNER)) { |
| 173 char name[sizeof(current->comm)]; |
| 174 printk_ratelimited(KERN_INFO "non-accessible hardlink" |
| 175 " creation was attempted by: %s (fsuid %d)\n", |
| 176 get_task_comm(name, current), |
| 177 cred->fsuid); |
| 178 rc = -EPERM; |
| 179 } |
| 180 |
| 181 return rc; |
| 182 } |
| 183 |
| 184 static struct security_operations yama_ops = { |
| 185 .name = "yama", |
| 186 |
| 187 .ptrace_access_check = yama_ptrace_access_check, |
| 188 .inode_follow_link = yama_inode_follow_link, |
| 189 .path_link = yama_path_link, |
| 190 }; |
| 191 |
| 192 #ifdef CONFIG_SYSCTL |
| 193 static int zero; |
| 194 static int one = 1; |
| 195 |
| 196 struct ctl_path yama_sysctl_path[] = { |
| 197 { .procname = "kernel", }, |
| 198 { .procname = "yama", }, |
| 199 { } |
| 200 }; |
| 201 |
| 202 static struct ctl_table yama_sysctl_table[] = { |
| 203 { |
| 204 .procname = "protected_sticky_symlinks", |
| 205 .data = &protected_sticky_symlinks, |
| 206 .maxlen = sizeof(int), |
| 207 .mode = 0644, |
| 208 .proc_handler = proc_dointvec_minmax, |
| 209 .extra1 = &zero, |
| 210 .extra2 = &one, |
| 211 }, |
| 212 { |
| 213 .procname = "protected_nonaccess_hardlinks", |
| 214 .data = &protected_nonaccess_hardlinks, |
| 215 .maxlen = sizeof(int), |
| 216 .mode = 0644, |
| 217 .proc_handler = proc_dointvec_minmax, |
| 218 .extra1 = &zero, |
| 219 .extra2 = &one, |
| 220 }, |
| 221 { |
| 222 .procname = "ptrace_scope", |
| 223 .data = &ptrace_scope, |
| 224 .maxlen = sizeof(int), |
| 225 .mode = 0644, |
| 226 .proc_handler = proc_dointvec_minmax, |
| 227 .extra1 = &zero, |
| 228 .extra2 = &one, |
| 229 }, |
| 230 { } |
| 231 }; |
| 232 #endif /* CONFIG_SYSCTL */ |
| 233 |
| 234 static __init int yama_init(void) |
| 235 { |
| 236 if (!security_module_enable(&yama_ops)) |
| 237 return 0; |
| 238 |
| 239 printk(KERN_INFO "Yama: becoming mindful.\n"); |
| 240 |
| 241 if (register_security(&yama_ops)) |
| 242 panic("Yama: kernel registration failed.\n"); |
| 243 |
| 244 #ifdef CONFIG_SYSCTL |
| 245 if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) |
| 246 panic("Yama: sysctl registration failed.\n"); |
| 247 #endif |
| 248 |
| 249 return 0; |
| 250 } |
| 251 |
| 252 security_initcall(yama_init); |
OLD | NEW |