Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: security/yama/yama_lsm.c

Issue 6677065: CHROMIUM: Pull in Yama LSM (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/kernel.git@master
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « security/yama/Makefile ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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);
OLDNEW
« no previous file with comments | « security/yama/Makefile ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698