diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/Makefile | 1 | ||||
-rw-r--r-- | security/commoncap.c | 6 | ||||
-rw-r--r-- | security/device_cgroup.c | 575 | ||||
-rw-r--r-- | security/dummy.c | 23 | ||||
-rw-r--r-- | security/keys/Makefile | 1 | ||||
-rw-r--r-- | security/keys/compat.c | 3 | ||||
-rw-r--r-- | security/keys/internal.h | 30 | ||||
-rw-r--r-- | security/keys/key.c | 86 | ||||
-rw-r--r-- | security/keys/keyctl.c | 126 | ||||
-rw-r--r-- | security/keys/keyring.c | 54 | ||||
-rw-r--r-- | security/keys/proc.c | 17 | ||||
-rw-r--r-- | security/keys/process_keys.c | 142 | ||||
-rw-r--r-- | security/keys/request_key.c | 50 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 13 | ||||
-rw-r--r-- | security/keys/sysctl.c | 50 | ||||
-rw-r--r-- | security/security.c | 19 | ||||
-rw-r--r-- | security/selinux/avc.c | 2 | ||||
-rw-r--r-- | security/selinux/hooks.c | 43 | ||||
-rw-r--r-- | security/selinux/include/security.h | 4 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 8 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 178 | ||||
-rw-r--r-- | security/smack/smackfs.c | 2 |
22 files changed, 1185 insertions, 248 deletions
diff --git a/security/Makefile b/security/Makefile index 9e8b02525014..7ef1107a7287 100644 --- a/security/Makefile +++ b/security/Makefile | |||
@@ -18,3 +18,4 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o | |||
18 | obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o | 18 | obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o |
19 | obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o | 19 | obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o |
20 | obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o | 20 | obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o |
21 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o | ||
diff --git a/security/commoncap.c b/security/commoncap.c index e8c3f5e46705..5edabc7542ae 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -383,8 +383,8 @@ int cap_bprm_secureexec (struct linux_binprm *bprm) | |||
383 | current->egid != current->gid); | 383 | current->egid != current->gid); |
384 | } | 384 | } |
385 | 385 | ||
386 | int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, | 386 | int cap_inode_setxattr(struct dentry *dentry, const char *name, |
387 | size_t size, int flags) | 387 | const void *value, size_t size, int flags) |
388 | { | 388 | { |
389 | if (!strcmp(name, XATTR_NAME_CAPS)) { | 389 | if (!strcmp(name, XATTR_NAME_CAPS)) { |
390 | if (!capable(CAP_SETFCAP)) | 390 | if (!capable(CAP_SETFCAP)) |
@@ -397,7 +397,7 @@ int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, | |||
397 | return 0; | 397 | return 0; |
398 | } | 398 | } |
399 | 399 | ||
400 | int cap_inode_removexattr(struct dentry *dentry, char *name) | 400 | int cap_inode_removexattr(struct dentry *dentry, const char *name) |
401 | { | 401 | { |
402 | if (!strcmp(name, XATTR_NAME_CAPS)) { | 402 | if (!strcmp(name, XATTR_NAME_CAPS)) { |
403 | if (!capable(CAP_SETFCAP)) | 403 | if (!capable(CAP_SETFCAP)) |
diff --git a/security/device_cgroup.c b/security/device_cgroup.c new file mode 100644 index 000000000000..4ea583689eec --- /dev/null +++ b/security/device_cgroup.c | |||
@@ -0,0 +1,575 @@ | |||
1 | /* | ||
2 | * dev_cgroup.c - device cgroup subsystem | ||
3 | * | ||
4 | * Copyright 2007 IBM Corp | ||
5 | */ | ||
6 | |||
7 | #include <linux/device_cgroup.h> | ||
8 | #include <linux/cgroup.h> | ||
9 | #include <linux/ctype.h> | ||
10 | #include <linux/list.h> | ||
11 | #include <linux/uaccess.h> | ||
12 | #include <linux/seq_file.h> | ||
13 | |||
14 | #define ACC_MKNOD 1 | ||
15 | #define ACC_READ 2 | ||
16 | #define ACC_WRITE 4 | ||
17 | #define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE) | ||
18 | |||
19 | #define DEV_BLOCK 1 | ||
20 | #define DEV_CHAR 2 | ||
21 | #define DEV_ALL 4 /* this represents all devices */ | ||
22 | |||
23 | /* | ||
24 | * whitelist locking rules: | ||
25 | * cgroup_lock() cannot be taken under dev_cgroup->lock. | ||
26 | * dev_cgroup->lock can be taken with or without cgroup_lock(). | ||
27 | * | ||
28 | * modifications always require cgroup_lock | ||
29 | * modifications to a list which is visible require the | ||
30 | * dev_cgroup->lock *and* cgroup_lock() | ||
31 | * walking the list requires dev_cgroup->lock or cgroup_lock(). | ||
32 | * | ||
33 | * reasoning: dev_whitelist_copy() needs to kmalloc, so needs | ||
34 | * a mutex, which the cgroup_lock() is. Since modifying | ||
35 | * a visible list requires both locks, either lock can be | ||
36 | * taken for walking the list. | ||
37 | */ | ||
38 | |||
39 | struct dev_whitelist_item { | ||
40 | u32 major, minor; | ||
41 | short type; | ||
42 | short access; | ||
43 | struct list_head list; | ||
44 | }; | ||
45 | |||
46 | struct dev_cgroup { | ||
47 | struct cgroup_subsys_state css; | ||
48 | struct list_head whitelist; | ||
49 | spinlock_t lock; | ||
50 | }; | ||
51 | |||
52 | static inline struct dev_cgroup *cgroup_to_devcgroup(struct cgroup *cgroup) | ||
53 | { | ||
54 | return container_of(cgroup_subsys_state(cgroup, devices_subsys_id), | ||
55 | struct dev_cgroup, css); | ||
56 | } | ||
57 | |||
58 | struct cgroup_subsys devices_subsys; | ||
59 | |||
60 | static int devcgroup_can_attach(struct cgroup_subsys *ss, | ||
61 | struct cgroup *new_cgroup, struct task_struct *task) | ||
62 | { | ||
63 | if (current != task && !capable(CAP_SYS_ADMIN)) | ||
64 | return -EPERM; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * called under cgroup_lock() | ||
71 | */ | ||
72 | static int dev_whitelist_copy(struct list_head *dest, struct list_head *orig) | ||
73 | { | ||
74 | struct dev_whitelist_item *wh, *tmp, *new; | ||
75 | |||
76 | list_for_each_entry(wh, orig, list) { | ||
77 | new = kmalloc(sizeof(*wh), GFP_KERNEL); | ||
78 | if (!new) | ||
79 | goto free_and_exit; | ||
80 | new->major = wh->major; | ||
81 | new->minor = wh->minor; | ||
82 | new->type = wh->type; | ||
83 | new->access = wh->access; | ||
84 | list_add_tail(&new->list, dest); | ||
85 | } | ||
86 | |||
87 | return 0; | ||
88 | |||
89 | free_and_exit: | ||
90 | list_for_each_entry_safe(wh, tmp, dest, list) { | ||
91 | list_del(&wh->list); | ||
92 | kfree(wh); | ||
93 | } | ||
94 | return -ENOMEM; | ||
95 | } | ||
96 | |||
97 | /* Stupid prototype - don't bother combining existing entries */ | ||
98 | /* | ||
99 | * called under cgroup_lock() | ||
100 | * since the list is visible to other tasks, we need the spinlock also | ||
101 | */ | ||
102 | static int dev_whitelist_add(struct dev_cgroup *dev_cgroup, | ||
103 | struct dev_whitelist_item *wh) | ||
104 | { | ||
105 | struct dev_whitelist_item *whcopy; | ||
106 | |||
107 | whcopy = kmalloc(sizeof(*whcopy), GFP_KERNEL); | ||
108 | if (!whcopy) | ||
109 | return -ENOMEM; | ||
110 | |||
111 | memcpy(whcopy, wh, sizeof(*whcopy)); | ||
112 | spin_lock(&dev_cgroup->lock); | ||
113 | list_add_tail(&whcopy->list, &dev_cgroup->whitelist); | ||
114 | spin_unlock(&dev_cgroup->lock); | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * called under cgroup_lock() | ||
120 | * since the list is visible to other tasks, we need the spinlock also | ||
121 | */ | ||
122 | static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup, | ||
123 | struct dev_whitelist_item *wh) | ||
124 | { | ||
125 | struct dev_whitelist_item *walk, *tmp; | ||
126 | |||
127 | spin_lock(&dev_cgroup->lock); | ||
128 | list_for_each_entry_safe(walk, tmp, &dev_cgroup->whitelist, list) { | ||
129 | if (walk->type == DEV_ALL) | ||
130 | goto remove; | ||
131 | if (walk->type != wh->type) | ||
132 | continue; | ||
133 | if (walk->major != ~0 && walk->major != wh->major) | ||
134 | continue; | ||
135 | if (walk->minor != ~0 && walk->minor != wh->minor) | ||
136 | continue; | ||
137 | |||
138 | remove: | ||
139 | walk->access &= ~wh->access; | ||
140 | if (!walk->access) { | ||
141 | list_del(&walk->list); | ||
142 | kfree(walk); | ||
143 | } | ||
144 | } | ||
145 | spin_unlock(&dev_cgroup->lock); | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * called from kernel/cgroup.c with cgroup_lock() held. | ||
150 | */ | ||
151 | static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss, | ||
152 | struct cgroup *cgroup) | ||
153 | { | ||
154 | struct dev_cgroup *dev_cgroup, *parent_dev_cgroup; | ||
155 | struct cgroup *parent_cgroup; | ||
156 | int ret; | ||
157 | |||
158 | dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL); | ||
159 | if (!dev_cgroup) | ||
160 | return ERR_PTR(-ENOMEM); | ||
161 | INIT_LIST_HEAD(&dev_cgroup->whitelist); | ||
162 | parent_cgroup = cgroup->parent; | ||
163 | |||
164 | if (parent_cgroup == NULL) { | ||
165 | struct dev_whitelist_item *wh; | ||
166 | wh = kmalloc(sizeof(*wh), GFP_KERNEL); | ||
167 | if (!wh) { | ||
168 | kfree(dev_cgroup); | ||
169 | return ERR_PTR(-ENOMEM); | ||
170 | } | ||
171 | wh->minor = wh->major = ~0; | ||
172 | wh->type = DEV_ALL; | ||
173 | wh->access = ACC_MKNOD | ACC_READ | ACC_WRITE; | ||
174 | list_add(&wh->list, &dev_cgroup->whitelist); | ||
175 | } else { | ||
176 | parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup); | ||
177 | ret = dev_whitelist_copy(&dev_cgroup->whitelist, | ||
178 | &parent_dev_cgroup->whitelist); | ||
179 | if (ret) { | ||
180 | kfree(dev_cgroup); | ||
181 | return ERR_PTR(ret); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | spin_lock_init(&dev_cgroup->lock); | ||
186 | return &dev_cgroup->css; | ||
187 | } | ||
188 | |||
189 | static void devcgroup_destroy(struct cgroup_subsys *ss, | ||
190 | struct cgroup *cgroup) | ||
191 | { | ||
192 | struct dev_cgroup *dev_cgroup; | ||
193 | struct dev_whitelist_item *wh, *tmp; | ||
194 | |||
195 | dev_cgroup = cgroup_to_devcgroup(cgroup); | ||
196 | list_for_each_entry_safe(wh, tmp, &dev_cgroup->whitelist, list) { | ||
197 | list_del(&wh->list); | ||
198 | kfree(wh); | ||
199 | } | ||
200 | kfree(dev_cgroup); | ||
201 | } | ||
202 | |||
203 | #define DEVCG_ALLOW 1 | ||
204 | #define DEVCG_DENY 2 | ||
205 | #define DEVCG_LIST 3 | ||
206 | |||
207 | #define MAJMINLEN 10 | ||
208 | #define ACCLEN 4 | ||
209 | |||
210 | static void set_access(char *acc, short access) | ||
211 | { | ||
212 | int idx = 0; | ||
213 | memset(acc, 0, ACCLEN); | ||
214 | if (access & ACC_READ) | ||
215 | acc[idx++] = 'r'; | ||
216 | if (access & ACC_WRITE) | ||
217 | acc[idx++] = 'w'; | ||
218 | if (access & ACC_MKNOD) | ||
219 | acc[idx++] = 'm'; | ||
220 | } | ||
221 | |||
222 | static char type_to_char(short type) | ||
223 | { | ||
224 | if (type == DEV_ALL) | ||
225 | return 'a'; | ||
226 | if (type == DEV_CHAR) | ||
227 | return 'c'; | ||
228 | if (type == DEV_BLOCK) | ||
229 | return 'b'; | ||
230 | return 'X'; | ||
231 | } | ||
232 | |||
233 | static void set_majmin(char *str, unsigned m) | ||
234 | { | ||
235 | memset(str, 0, MAJMINLEN); | ||
236 | if (m == ~0) | ||
237 | sprintf(str, "*"); | ||
238 | else | ||
239 | snprintf(str, MAJMINLEN, "%d", m); | ||
240 | } | ||
241 | |||
242 | static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft, | ||
243 | struct seq_file *m) | ||
244 | { | ||
245 | struct dev_cgroup *devcgroup = cgroup_to_devcgroup(cgroup); | ||
246 | struct dev_whitelist_item *wh; | ||
247 | char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN]; | ||
248 | |||
249 | spin_lock(&devcgroup->lock); | ||
250 | list_for_each_entry(wh, &devcgroup->whitelist, list) { | ||
251 | set_access(acc, wh->access); | ||
252 | set_majmin(maj, wh->major); | ||
253 | set_majmin(min, wh->minor); | ||
254 | seq_printf(m, "%c %s:%s %s\n", type_to_char(wh->type), | ||
255 | maj, min, acc); | ||
256 | } | ||
257 | spin_unlock(&devcgroup->lock); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * may_access_whitelist: | ||
264 | * does the access granted to dev_cgroup c contain the access | ||
265 | * requested in whitelist item refwh. | ||
266 | * return 1 if yes, 0 if no. | ||
267 | * call with c->lock held | ||
268 | */ | ||
269 | static int may_access_whitelist(struct dev_cgroup *c, | ||
270 | struct dev_whitelist_item *refwh) | ||
271 | { | ||
272 | struct dev_whitelist_item *whitem; | ||
273 | |||
274 | list_for_each_entry(whitem, &c->whitelist, list) { | ||
275 | if (whitem->type & DEV_ALL) | ||
276 | return 1; | ||
277 | if ((refwh->type & DEV_BLOCK) && !(whitem->type & DEV_BLOCK)) | ||
278 | continue; | ||
279 | if ((refwh->type & DEV_CHAR) && !(whitem->type & DEV_CHAR)) | ||
280 | continue; | ||
281 | if (whitem->major != ~0 && whitem->major != refwh->major) | ||
282 | continue; | ||
283 | if (whitem->minor != ~0 && whitem->minor != refwh->minor) | ||
284 | continue; | ||
285 | if (refwh->access & (~(whitem->access | ACC_MASK))) | ||
286 | continue; | ||
287 | return 1; | ||
288 | } | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * parent_has_perm: | ||
294 | * when adding a new allow rule to a device whitelist, the rule | ||
295 | * must be allowed in the parent device | ||
296 | */ | ||
297 | static int parent_has_perm(struct cgroup *childcg, | ||
298 | struct dev_whitelist_item *wh) | ||
299 | { | ||
300 | struct cgroup *pcg = childcg->parent; | ||
301 | struct dev_cgroup *parent; | ||
302 | int ret; | ||
303 | |||
304 | if (!pcg) | ||
305 | return 1; | ||
306 | parent = cgroup_to_devcgroup(pcg); | ||
307 | spin_lock(&parent->lock); | ||
308 | ret = may_access_whitelist(parent, wh); | ||
309 | spin_unlock(&parent->lock); | ||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * Modify the whitelist using allow/deny rules. | ||
315 | * CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD | ||
316 | * so we can give a container CAP_MKNOD to let it create devices but not | ||
317 | * modify the whitelist. | ||
318 | * It seems likely we'll want to add a CAP_CONTAINER capability to allow | ||
319 | * us to also grant CAP_SYS_ADMIN to containers without giving away the | ||
320 | * device whitelist controls, but for now we'll stick with CAP_SYS_ADMIN | ||
321 | * | ||
322 | * Taking rules away is always allowed (given CAP_SYS_ADMIN). Granting | ||
323 | * new access is only allowed if you're in the top-level cgroup, or your | ||
324 | * parent cgroup has the access you're asking for. | ||
325 | */ | ||
326 | static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft, | ||
327 | struct file *file, const char __user *userbuf, | ||
328 | size_t nbytes, loff_t *ppos) | ||
329 | { | ||
330 | struct cgroup *cur_cgroup; | ||
331 | struct dev_cgroup *devcgroup, *cur_devcgroup; | ||
332 | int filetype = cft->private; | ||
333 | char *buffer, *b; | ||
334 | int retval = 0, count; | ||
335 | struct dev_whitelist_item wh; | ||
336 | |||
337 | if (!capable(CAP_SYS_ADMIN)) | ||
338 | return -EPERM; | ||
339 | |||
340 | devcgroup = cgroup_to_devcgroup(cgroup); | ||
341 | cur_cgroup = task_cgroup(current, devices_subsys.subsys_id); | ||
342 | cur_devcgroup = cgroup_to_devcgroup(cur_cgroup); | ||
343 | |||
344 | buffer = kmalloc(nbytes+1, GFP_KERNEL); | ||
345 | if (!buffer) | ||
346 | return -ENOMEM; | ||
347 | |||
348 | if (copy_from_user(buffer, userbuf, nbytes)) { | ||
349 | retval = -EFAULT; | ||
350 | goto out1; | ||
351 | } | ||
352 | buffer[nbytes] = 0; /* nul-terminate */ | ||
353 | |||
354 | cgroup_lock(); | ||
355 | if (cgroup_is_removed(cgroup)) { | ||
356 | retval = -ENODEV; | ||
357 | goto out2; | ||
358 | } | ||
359 | |||
360 | memset(&wh, 0, sizeof(wh)); | ||
361 | b = buffer; | ||
362 | |||
363 | switch (*b) { | ||
364 | case 'a': | ||
365 | wh.type = DEV_ALL; | ||
366 | wh.access = ACC_MASK; | ||
367 | goto handle; | ||
368 | case 'b': | ||
369 | wh.type = DEV_BLOCK; | ||
370 | break; | ||
371 | case 'c': | ||
372 | wh.type = DEV_CHAR; | ||
373 | break; | ||
374 | default: | ||
375 | retval = -EINVAL; | ||
376 | goto out2; | ||
377 | } | ||
378 | b++; | ||
379 | if (!isspace(*b)) { | ||
380 | retval = -EINVAL; | ||
381 | goto out2; | ||
382 | } | ||
383 | b++; | ||
384 | if (*b == '*') { | ||
385 | wh.major = ~0; | ||
386 | b++; | ||
387 | } else if (isdigit(*b)) { | ||
388 | wh.major = 0; | ||
389 | while (isdigit(*b)) { | ||
390 | wh.major = wh.major*10+(*b-'0'); | ||
391 | b++; | ||
392 | } | ||
393 | } else { | ||
394 | retval = -EINVAL; | ||
395 | goto out2; | ||
396 | } | ||
397 | if (*b != ':') { | ||
398 | retval = -EINVAL; | ||
399 | goto out2; | ||
400 | } | ||
401 | b++; | ||
402 | |||
403 | /* read minor */ | ||
404 | if (*b == '*') { | ||
405 | wh.minor = ~0; | ||
406 | b++; | ||
407 | } else if (isdigit(*b)) { | ||
408 | wh.minor = 0; | ||
409 | while (isdigit(*b)) { | ||
410 | wh.minor = wh.minor*10+(*b-'0'); | ||
411 | b++; | ||
412 | } | ||
413 | } else { | ||
414 | retval = -EINVAL; | ||
415 | goto out2; | ||
416 | } | ||
417 | if (!isspace(*b)) { | ||
418 | retval = -EINVAL; | ||
419 | goto out2; | ||
420 | } | ||
421 | for (b++, count = 0; count < 3; count++, b++) { | ||
422 | switch (*b) { | ||
423 | case 'r': | ||
424 | wh.access |= ACC_READ; | ||
425 | break; | ||
426 | case 'w': | ||
427 | wh.access |= ACC_WRITE; | ||
428 | break; | ||
429 | case 'm': | ||
430 | wh.access |= ACC_MKNOD; | ||
431 | break; | ||
432 | case '\n': | ||
433 | case '\0': | ||
434 | count = 3; | ||
435 | break; | ||
436 | default: | ||
437 | retval = -EINVAL; | ||
438 | goto out2; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | handle: | ||
443 | retval = 0; | ||
444 | switch (filetype) { | ||
445 | case DEVCG_ALLOW: | ||
446 | if (!parent_has_perm(cgroup, &wh)) | ||
447 | retval = -EPERM; | ||
448 | else | ||
449 | retval = dev_whitelist_add(devcgroup, &wh); | ||
450 | break; | ||
451 | case DEVCG_DENY: | ||
452 | dev_whitelist_rm(devcgroup, &wh); | ||
453 | break; | ||
454 | default: | ||
455 | retval = -EINVAL; | ||
456 | goto out2; | ||
457 | } | ||
458 | |||
459 | if (retval == 0) | ||
460 | retval = nbytes; | ||
461 | |||
462 | out2: | ||
463 | cgroup_unlock(); | ||
464 | out1: | ||
465 | kfree(buffer); | ||
466 | return retval; | ||
467 | } | ||
468 | |||
469 | static struct cftype dev_cgroup_files[] = { | ||
470 | { | ||
471 | .name = "allow", | ||
472 | .write = devcgroup_access_write, | ||
473 | .private = DEVCG_ALLOW, | ||
474 | }, | ||
475 | { | ||
476 | .name = "deny", | ||
477 | .write = devcgroup_access_write, | ||
478 | .private = DEVCG_DENY, | ||
479 | }, | ||
480 | { | ||
481 | .name = "list", | ||
482 | .read_seq_string = devcgroup_seq_read, | ||
483 | .private = DEVCG_LIST, | ||
484 | }, | ||
485 | }; | ||
486 | |||
487 | static int devcgroup_populate(struct cgroup_subsys *ss, | ||
488 | struct cgroup *cgroup) | ||
489 | { | ||
490 | return cgroup_add_files(cgroup, ss, dev_cgroup_files, | ||
491 | ARRAY_SIZE(dev_cgroup_files)); | ||
492 | } | ||
493 | |||
494 | struct cgroup_subsys devices_subsys = { | ||
495 | .name = "devices", | ||
496 | .can_attach = devcgroup_can_attach, | ||
497 | .create = devcgroup_create, | ||
498 | .destroy = devcgroup_destroy, | ||
499 | .populate = devcgroup_populate, | ||
500 | .subsys_id = devices_subsys_id, | ||
501 | }; | ||
502 | |||
503 | int devcgroup_inode_permission(struct inode *inode, int mask) | ||
504 | { | ||
505 | struct cgroup *cgroup; | ||
506 | struct dev_cgroup *dev_cgroup; | ||
507 | struct dev_whitelist_item *wh; | ||
508 | |||
509 | dev_t device = inode->i_rdev; | ||
510 | if (!device) | ||
511 | return 0; | ||
512 | if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode)) | ||
513 | return 0; | ||
514 | cgroup = task_cgroup(current, devices_subsys.subsys_id); | ||
515 | dev_cgroup = cgroup_to_devcgroup(cgroup); | ||
516 | if (!dev_cgroup) | ||
517 | return 0; | ||
518 | |||
519 | spin_lock(&dev_cgroup->lock); | ||
520 | list_for_each_entry(wh, &dev_cgroup->whitelist, list) { | ||
521 | if (wh->type & DEV_ALL) | ||
522 | goto acc_check; | ||
523 | if ((wh->type & DEV_BLOCK) && !S_ISBLK(inode->i_mode)) | ||
524 | continue; | ||
525 | if ((wh->type & DEV_CHAR) && !S_ISCHR(inode->i_mode)) | ||
526 | continue; | ||
527 | if (wh->major != ~0 && wh->major != imajor(inode)) | ||
528 | continue; | ||
529 | if (wh->minor != ~0 && wh->minor != iminor(inode)) | ||
530 | continue; | ||
531 | acc_check: | ||
532 | if ((mask & MAY_WRITE) && !(wh->access & ACC_WRITE)) | ||
533 | continue; | ||
534 | if ((mask & MAY_READ) && !(wh->access & ACC_READ)) | ||
535 | continue; | ||
536 | spin_unlock(&dev_cgroup->lock); | ||
537 | return 0; | ||
538 | } | ||
539 | spin_unlock(&dev_cgroup->lock); | ||
540 | |||
541 | return -EPERM; | ||
542 | } | ||
543 | |||
544 | int devcgroup_inode_mknod(int mode, dev_t dev) | ||
545 | { | ||
546 | struct cgroup *cgroup; | ||
547 | struct dev_cgroup *dev_cgroup; | ||
548 | struct dev_whitelist_item *wh; | ||
549 | |||
550 | cgroup = task_cgroup(current, devices_subsys.subsys_id); | ||
551 | dev_cgroup = cgroup_to_devcgroup(cgroup); | ||
552 | if (!dev_cgroup) | ||
553 | return 0; | ||
554 | |||
555 | spin_lock(&dev_cgroup->lock); | ||
556 | list_for_each_entry(wh, &dev_cgroup->whitelist, list) { | ||
557 | if (wh->type & DEV_ALL) | ||
558 | goto acc_check; | ||
559 | if ((wh->type & DEV_BLOCK) && !S_ISBLK(mode)) | ||
560 | continue; | ||
561 | if ((wh->type & DEV_CHAR) && !S_ISCHR(mode)) | ||
562 | continue; | ||
563 | if (wh->major != ~0 && wh->major != MAJOR(dev)) | ||
564 | continue; | ||
565 | if (wh->minor != ~0 && wh->minor != MINOR(dev)) | ||
566 | continue; | ||
567 | acc_check: | ||
568 | if (!(wh->access & ACC_MKNOD)) | ||
569 | continue; | ||
570 | spin_unlock(&dev_cgroup->lock); | ||
571 | return 0; | ||
572 | } | ||
573 | spin_unlock(&dev_cgroup->lock); | ||
574 | return -EPERM; | ||
575 | } | ||
diff --git a/security/dummy.c b/security/dummy.c index 58d4dd1af5c7..f50c6c3c32c9 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -365,8 +365,8 @@ static void dummy_inode_delete (struct inode *ino) | |||
365 | return; | 365 | return; |
366 | } | 366 | } |
367 | 367 | ||
368 | static int dummy_inode_setxattr (struct dentry *dentry, char *name, void *value, | 368 | static int dummy_inode_setxattr (struct dentry *dentry, const char *name, |
369 | size_t size, int flags) | 369 | const void *value, size_t size, int flags) |
370 | { | 370 | { |
371 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 371 | if (!strncmp(name, XATTR_SECURITY_PREFIX, |
372 | sizeof(XATTR_SECURITY_PREFIX) - 1) && | 372 | sizeof(XATTR_SECURITY_PREFIX) - 1) && |
@@ -375,12 +375,13 @@ static int dummy_inode_setxattr (struct dentry *dentry, char *name, void *value, | |||
375 | return 0; | 375 | return 0; |
376 | } | 376 | } |
377 | 377 | ||
378 | static void dummy_inode_post_setxattr (struct dentry *dentry, char *name, void *value, | 378 | static void dummy_inode_post_setxattr (struct dentry *dentry, const char *name, |
379 | size_t size, int flags) | 379 | const void *value, size_t size, |
380 | int flags) | ||
380 | { | 381 | { |
381 | } | 382 | } |
382 | 383 | ||
383 | static int dummy_inode_getxattr (struct dentry *dentry, char *name) | 384 | static int dummy_inode_getxattr (struct dentry *dentry, const char *name) |
384 | { | 385 | { |
385 | return 0; | 386 | return 0; |
386 | } | 387 | } |
@@ -390,7 +391,7 @@ static int dummy_inode_listxattr (struct dentry *dentry) | |||
390 | return 0; | 391 | return 0; |
391 | } | 392 | } |
392 | 393 | ||
393 | static int dummy_inode_removexattr (struct dentry *dentry, char *name) | 394 | static int dummy_inode_removexattr (struct dentry *dentry, const char *name) |
394 | { | 395 | { |
395 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 396 | if (!strncmp(name, XATTR_SECURITY_PREFIX, |
396 | sizeof(XATTR_SECURITY_PREFIX) - 1) && | 397 | sizeof(XATTR_SECURITY_PREFIX) - 1) && |
@@ -967,7 +968,7 @@ static int dummy_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | |||
967 | return -EOPNOTSUPP; | 968 | return -EOPNOTSUPP; |
968 | } | 969 | } |
969 | 970 | ||
970 | static int dummy_secctx_to_secid(char *secdata, u32 seclen, u32 *secid) | 971 | static int dummy_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) |
971 | { | 972 | { |
972 | return -EOPNOTSUPP; | 973 | return -EOPNOTSUPP; |
973 | } | 974 | } |
@@ -993,6 +994,13 @@ static inline int dummy_key_permission(key_ref_t key_ref, | |||
993 | { | 994 | { |
994 | return 0; | 995 | return 0; |
995 | } | 996 | } |
997 | |||
998 | static int dummy_key_getsecurity(struct key *key, char **_buffer) | ||
999 | { | ||
1000 | *_buffer = NULL; | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
996 | #endif /* CONFIG_KEYS */ | 1004 | #endif /* CONFIG_KEYS */ |
997 | 1005 | ||
998 | #ifdef CONFIG_AUDIT | 1006 | #ifdef CONFIG_AUDIT |
@@ -1209,6 +1217,7 @@ void security_fixup_ops (struct security_operations *ops) | |||
1209 | set_to_dummy_if_null(ops, key_alloc); | 1217 | set_to_dummy_if_null(ops, key_alloc); |
1210 | set_to_dummy_if_null(ops, key_free); | 1218 | set_to_dummy_if_null(ops, key_free); |
1211 | set_to_dummy_if_null(ops, key_permission); | 1219 | set_to_dummy_if_null(ops, key_permission); |
1220 | set_to_dummy_if_null(ops, key_getsecurity); | ||
1212 | #endif /* CONFIG_KEYS */ | 1221 | #endif /* CONFIG_KEYS */ |
1213 | #ifdef CONFIG_AUDIT | 1222 | #ifdef CONFIG_AUDIT |
1214 | set_to_dummy_if_null(ops, audit_rule_init); | 1223 | set_to_dummy_if_null(ops, audit_rule_init); |
diff --git a/security/keys/Makefile b/security/keys/Makefile index 5145adfb6a05..747a464943af 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
@@ -14,3 +14,4 @@ obj-y := \ | |||
14 | 14 | ||
15 | obj-$(CONFIG_KEYS_COMPAT) += compat.o | 15 | obj-$(CONFIG_KEYS_COMPAT) += compat.o |
16 | obj-$(CONFIG_PROC_FS) += proc.o | 16 | obj-$(CONFIG_PROC_FS) += proc.o |
17 | obj-$(CONFIG_SYSCTL) += sysctl.o | ||
diff --git a/security/keys/compat.c b/security/keys/compat.c index e10ec995f275..c766c68a63bc 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
@@ -79,6 +79,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
79 | case KEYCTL_ASSUME_AUTHORITY: | 79 | case KEYCTL_ASSUME_AUTHORITY: |
80 | return keyctl_assume_authority(arg2); | 80 | return keyctl_assume_authority(arg2); |
81 | 81 | ||
82 | case KEYCTL_GET_SECURITY: | ||
83 | return keyctl_get_security(arg2, compat_ptr(arg3), arg4); | ||
84 | |||
82 | default: | 85 | default: |
83 | return -EOPNOTSUPP; | 86 | return -EOPNOTSUPP; |
84 | } | 87 | } |
diff --git a/security/keys/internal.h b/security/keys/internal.h index 7d894ef70370..8c05587f5018 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -57,10 +57,6 @@ struct key_user { | |||
57 | int qnbytes; /* number of bytes allocated to this user */ | 57 | int qnbytes; /* number of bytes allocated to this user */ |
58 | }; | 58 | }; |
59 | 59 | ||
60 | #define KEYQUOTA_MAX_KEYS 100 | ||
61 | #define KEYQUOTA_MAX_BYTES 10000 | ||
62 | #define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */ | ||
63 | |||
64 | extern struct rb_root key_user_tree; | 60 | extern struct rb_root key_user_tree; |
65 | extern spinlock_t key_user_lock; | 61 | extern spinlock_t key_user_lock; |
66 | extern struct key_user root_key_user; | 62 | extern struct key_user root_key_user; |
@@ -68,6 +64,16 @@ extern struct key_user root_key_user; | |||
68 | extern struct key_user *key_user_lookup(uid_t uid); | 64 | extern struct key_user *key_user_lookup(uid_t uid); |
69 | extern void key_user_put(struct key_user *user); | 65 | extern void key_user_put(struct key_user *user); |
70 | 66 | ||
67 | /* | ||
68 | * key quota limits | ||
69 | * - root has its own separate limits to everyone else | ||
70 | */ | ||
71 | extern unsigned key_quota_root_maxkeys; | ||
72 | extern unsigned key_quota_root_maxbytes; | ||
73 | extern unsigned key_quota_maxkeys; | ||
74 | extern unsigned key_quota_maxbytes; | ||
75 | |||
76 | #define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */ | ||
71 | 77 | ||
72 | 78 | ||
73 | extern struct rb_root key_serial_tree; | 79 | extern struct rb_root key_serial_tree; |
@@ -77,8 +83,6 @@ extern struct mutex key_construction_mutex; | |||
77 | extern wait_queue_head_t request_key_conswq; | 83 | extern wait_queue_head_t request_key_conswq; |
78 | 84 | ||
79 | 85 | ||
80 | extern void keyring_publish_name(struct key *keyring); | ||
81 | |||
82 | extern int __key_link(struct key *keyring, struct key *key); | 86 | extern int __key_link(struct key *keyring, struct key *key); |
83 | 87 | ||
84 | extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, | 88 | extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, |
@@ -102,14 +106,15 @@ extern key_ref_t search_process_keyrings(struct key_type *type, | |||
102 | key_match_func_t match, | 106 | key_match_func_t match, |
103 | struct task_struct *tsk); | 107 | struct task_struct *tsk); |
104 | 108 | ||
105 | extern struct key *find_keyring_by_name(const char *name, key_serial_t bound); | 109 | extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); |
106 | 110 | ||
107 | extern int install_thread_keyring(struct task_struct *tsk); | 111 | extern int install_thread_keyring(struct task_struct *tsk); |
108 | extern int install_process_keyring(struct task_struct *tsk); | 112 | extern int install_process_keyring(struct task_struct *tsk); |
109 | 113 | ||
110 | extern struct key *request_key_and_link(struct key_type *type, | 114 | extern struct key *request_key_and_link(struct key_type *type, |
111 | const char *description, | 115 | const char *description, |
112 | const char *callout_info, | 116 | const void *callout_info, |
117 | size_t callout_len, | ||
113 | void *aux, | 118 | void *aux, |
114 | struct key *dest_keyring, | 119 | struct key *dest_keyring, |
115 | unsigned long flags); | 120 | unsigned long flags); |
@@ -120,13 +125,15 @@ extern struct key *request_key_and_link(struct key_type *type, | |||
120 | struct request_key_auth { | 125 | struct request_key_auth { |
121 | struct key *target_key; | 126 | struct key *target_key; |
122 | struct task_struct *context; | 127 | struct task_struct *context; |
123 | char *callout_info; | 128 | void *callout_info; |
129 | size_t callout_len; | ||
124 | pid_t pid; | 130 | pid_t pid; |
125 | }; | 131 | }; |
126 | 132 | ||
127 | extern struct key_type key_type_request_key_auth; | 133 | extern struct key_type key_type_request_key_auth; |
128 | extern struct key *request_key_auth_new(struct key *target, | 134 | extern struct key *request_key_auth_new(struct key *target, |
129 | const char *callout_info); | 135 | const void *callout_info, |
136 | size_t callout_len); | ||
130 | 137 | ||
131 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); | 138 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); |
132 | 139 | ||
@@ -152,7 +159,8 @@ extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); | |||
152 | extern long keyctl_set_reqkey_keyring(int); | 159 | extern long keyctl_set_reqkey_keyring(int); |
153 | extern long keyctl_set_timeout(key_serial_t, unsigned); | 160 | extern long keyctl_set_timeout(key_serial_t, unsigned); |
154 | extern long keyctl_assume_authority(key_serial_t); | 161 | extern long keyctl_assume_authority(key_serial_t); |
155 | 162 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, | |
163 | size_t buflen); | ||
156 | 164 | ||
157 | /* | 165 | /* |
158 | * debugging key validation | 166 | * debugging key validation |
diff --git a/security/keys/key.c b/security/keys/key.c index 654d23baf352..14948cf83ef6 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* Basic authentication token and access key management | 1 | /* Basic authentication token and access key management |
2 | * | 2 | * |
3 | * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -27,6 +27,11 @@ DEFINE_SPINLOCK(key_serial_lock); | |||
27 | struct rb_root key_user_tree; /* tree of quota records indexed by UID */ | 27 | struct rb_root key_user_tree; /* tree of quota records indexed by UID */ |
28 | DEFINE_SPINLOCK(key_user_lock); | 28 | DEFINE_SPINLOCK(key_user_lock); |
29 | 29 | ||
30 | unsigned int key_quota_root_maxkeys = 200; /* root's key count quota */ | ||
31 | unsigned int key_quota_root_maxbytes = 20000; /* root's key space quota */ | ||
32 | unsigned int key_quota_maxkeys = 200; /* general key count quota */ | ||
33 | unsigned int key_quota_maxbytes = 20000; /* general key space quota */ | ||
34 | |||
30 | static LIST_HEAD(key_types_list); | 35 | static LIST_HEAD(key_types_list); |
31 | static DECLARE_RWSEM(key_types_sem); | 36 | static DECLARE_RWSEM(key_types_sem); |
32 | 37 | ||
@@ -139,36 +144,6 @@ void key_user_put(struct key_user *user) | |||
139 | 144 | ||
140 | /*****************************************************************************/ | 145 | /*****************************************************************************/ |
141 | /* | 146 | /* |
142 | * insert a key with a fixed serial number | ||
143 | */ | ||
144 | static void __init __key_insert_serial(struct key *key) | ||
145 | { | ||
146 | struct rb_node *parent, **p; | ||
147 | struct key *xkey; | ||
148 | |||
149 | parent = NULL; | ||
150 | p = &key_serial_tree.rb_node; | ||
151 | |||
152 | while (*p) { | ||
153 | parent = *p; | ||
154 | xkey = rb_entry(parent, struct key, serial_node); | ||
155 | |||
156 | if (key->serial < xkey->serial) | ||
157 | p = &(*p)->rb_left; | ||
158 | else if (key->serial > xkey->serial) | ||
159 | p = &(*p)->rb_right; | ||
160 | else | ||
161 | BUG(); | ||
162 | } | ||
163 | |||
164 | /* we've found a suitable hole - arrange for this key to occupy it */ | ||
165 | rb_link_node(&key->serial_node, parent, p); | ||
166 | rb_insert_color(&key->serial_node, &key_serial_tree); | ||
167 | |||
168 | } /* end __key_insert_serial() */ | ||
169 | |||
170 | /*****************************************************************************/ | ||
171 | /* | ||
172 | * assign a key the next unique serial number | 147 | * assign a key the next unique serial number |
173 | * - these are assigned randomly to avoid security issues through covert | 148 | * - these are assigned randomly to avoid security issues through covert |
174 | * channel problems | 149 | * channel problems |
@@ -266,11 +241,16 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
266 | /* check that the user's quota permits allocation of another key and | 241 | /* check that the user's quota permits allocation of another key and |
267 | * its description */ | 242 | * its description */ |
268 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { | 243 | if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { |
244 | unsigned maxkeys = (uid == 0) ? | ||
245 | key_quota_root_maxkeys : key_quota_maxkeys; | ||
246 | unsigned maxbytes = (uid == 0) ? | ||
247 | key_quota_root_maxbytes : key_quota_maxbytes; | ||
248 | |||
269 | spin_lock(&user->lock); | 249 | spin_lock(&user->lock); |
270 | if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { | 250 | if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { |
271 | if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || | 251 | if (user->qnkeys + 1 >= maxkeys || |
272 | user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES | 252 | user->qnbytes + quotalen >= maxbytes || |
273 | ) | 253 | user->qnbytes + quotalen < user->qnbytes) |
274 | goto no_quota; | 254 | goto no_quota; |
275 | } | 255 | } |
276 | 256 | ||
@@ -375,11 +355,14 @@ int key_payload_reserve(struct key *key, size_t datalen) | |||
375 | 355 | ||
376 | /* contemplate the quota adjustment */ | 356 | /* contemplate the quota adjustment */ |
377 | if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 357 | if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
358 | unsigned maxbytes = (key->user->uid == 0) ? | ||
359 | key_quota_root_maxbytes : key_quota_maxbytes; | ||
360 | |||
378 | spin_lock(&key->user->lock); | 361 | spin_lock(&key->user->lock); |
379 | 362 | ||
380 | if (delta > 0 && | 363 | if (delta > 0 && |
381 | key->user->qnbytes + delta > KEYQUOTA_MAX_BYTES | 364 | (key->user->qnbytes + delta >= maxbytes || |
382 | ) { | 365 | key->user->qnbytes + delta < key->user->qnbytes)) { |
383 | ret = -EDQUOT; | 366 | ret = -EDQUOT; |
384 | } | 367 | } |
385 | else { | 368 | else { |
@@ -757,11 +740,11 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
757 | const char *description, | 740 | const char *description, |
758 | const void *payload, | 741 | const void *payload, |
759 | size_t plen, | 742 | size_t plen, |
743 | key_perm_t perm, | ||
760 | unsigned long flags) | 744 | unsigned long flags) |
761 | { | 745 | { |
762 | struct key_type *ktype; | 746 | struct key_type *ktype; |
763 | struct key *keyring, *key = NULL; | 747 | struct key *keyring, *key = NULL; |
764 | key_perm_t perm; | ||
765 | key_ref_t key_ref; | 748 | key_ref_t key_ref; |
766 | int ret; | 749 | int ret; |
767 | 750 | ||
@@ -806,15 +789,17 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
806 | goto found_matching_key; | 789 | goto found_matching_key; |
807 | } | 790 | } |
808 | 791 | ||
809 | /* decide on the permissions we want */ | 792 | /* if the client doesn't provide, decide on the permissions we want */ |
810 | perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; | 793 | if (perm == KEY_PERM_UNDEF) { |
811 | perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR; | 794 | perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; |
795 | perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR; | ||
812 | 796 | ||
813 | if (ktype->read) | 797 | if (ktype->read) |
814 | perm |= KEY_POS_READ | KEY_USR_READ; | 798 | perm |= KEY_POS_READ | KEY_USR_READ; |
815 | 799 | ||
816 | if (ktype == &key_type_keyring || ktype->update) | 800 | if (ktype == &key_type_keyring || ktype->update) |
817 | perm |= KEY_USR_WRITE; | 801 | perm |= KEY_USR_WRITE; |
802 | } | ||
818 | 803 | ||
819 | /* allocate a new key */ | 804 | /* allocate a new key */ |
820 | key = key_alloc(ktype, description, current->fsuid, current->fsgid, | 805 | key = key_alloc(ktype, description, current->fsuid, current->fsgid, |
@@ -1018,17 +1003,4 @@ void __init key_init(void) | |||
1018 | rb_insert_color(&root_key_user.node, | 1003 | rb_insert_color(&root_key_user.node, |
1019 | &key_user_tree); | 1004 | &key_user_tree); |
1020 | 1005 | ||
1021 | /* record root's user standard keyrings */ | ||
1022 | key_check(&root_user_keyring); | ||
1023 | key_check(&root_session_keyring); | ||
1024 | |||
1025 | __key_insert_serial(&root_user_keyring); | ||
1026 | __key_insert_serial(&root_session_keyring); | ||
1027 | |||
1028 | keyring_publish_name(&root_user_keyring); | ||
1029 | keyring_publish_name(&root_session_keyring); | ||
1030 | |||
1031 | /* link the two root keyrings together */ | ||
1032 | key_link(&root_session_keyring, &root_user_keyring); | ||
1033 | |||
1034 | } /* end key_init() */ | 1006 | } /* end key_init() */ |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index d9ca15c109cc..acc9c89e40a8 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/capability.h> | 19 | #include <linux/capability.h> |
20 | #include <linux/string.h> | 20 | #include <linux/string.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/vmalloc.h> | ||
23 | #include <linux/security.h> | ||
22 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
23 | #include "internal.h" | 25 | #include "internal.h" |
24 | 26 | ||
@@ -62,9 +64,10 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
62 | char type[32], *description; | 64 | char type[32], *description; |
63 | void *payload; | 65 | void *payload; |
64 | long ret; | 66 | long ret; |
67 | bool vm; | ||
65 | 68 | ||
66 | ret = -EINVAL; | 69 | ret = -EINVAL; |
67 | if (plen > 32767) | 70 | if (plen > 1024 * 1024 - 1) |
68 | goto error; | 71 | goto error; |
69 | 72 | ||
70 | /* draw all the data into kernel space */ | 73 | /* draw all the data into kernel space */ |
@@ -81,11 +84,18 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
81 | /* pull the payload in if one was supplied */ | 84 | /* pull the payload in if one was supplied */ |
82 | payload = NULL; | 85 | payload = NULL; |
83 | 86 | ||
87 | vm = false; | ||
84 | if (_payload) { | 88 | if (_payload) { |
85 | ret = -ENOMEM; | 89 | ret = -ENOMEM; |
86 | payload = kmalloc(plen, GFP_KERNEL); | 90 | payload = kmalloc(plen, GFP_KERNEL); |
87 | if (!payload) | 91 | if (!payload) { |
88 | goto error2; | 92 | if (plen <= PAGE_SIZE) |
93 | goto error2; | ||
94 | vm = true; | ||
95 | payload = vmalloc(plen); | ||
96 | if (!payload) | ||
97 | goto error2; | ||
98 | } | ||
89 | 99 | ||
90 | ret = -EFAULT; | 100 | ret = -EFAULT; |
91 | if (copy_from_user(payload, _payload, plen) != 0) | 101 | if (copy_from_user(payload, _payload, plen) != 0) |
@@ -102,7 +112,8 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
102 | /* create or update the requested key and add it to the target | 112 | /* create or update the requested key and add it to the target |
103 | * keyring */ | 113 | * keyring */ |
104 | key_ref = key_create_or_update(keyring_ref, type, description, | 114 | key_ref = key_create_or_update(keyring_ref, type, description, |
105 | payload, plen, KEY_ALLOC_IN_QUOTA); | 115 | payload, plen, KEY_PERM_UNDEF, |
116 | KEY_ALLOC_IN_QUOTA); | ||
106 | if (!IS_ERR(key_ref)) { | 117 | if (!IS_ERR(key_ref)) { |
107 | ret = key_ref_to_ptr(key_ref)->serial; | 118 | ret = key_ref_to_ptr(key_ref)->serial; |
108 | key_ref_put(key_ref); | 119 | key_ref_put(key_ref); |
@@ -113,7 +124,10 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
113 | 124 | ||
114 | key_ref_put(keyring_ref); | 125 | key_ref_put(keyring_ref); |
115 | error3: | 126 | error3: |
116 | kfree(payload); | 127 | if (!vm) |
128 | kfree(payload); | ||
129 | else | ||
130 | vfree(payload); | ||
117 | error2: | 131 | error2: |
118 | kfree(description); | 132 | kfree(description); |
119 | error: | 133 | error: |
@@ -140,6 +154,7 @@ asmlinkage long sys_request_key(const char __user *_type, | |||
140 | struct key_type *ktype; | 154 | struct key_type *ktype; |
141 | struct key *key; | 155 | struct key *key; |
142 | key_ref_t dest_ref; | 156 | key_ref_t dest_ref; |
157 | size_t callout_len; | ||
143 | char type[32], *description, *callout_info; | 158 | char type[32], *description, *callout_info; |
144 | long ret; | 159 | long ret; |
145 | 160 | ||
@@ -157,12 +172,14 @@ asmlinkage long sys_request_key(const char __user *_type, | |||
157 | 172 | ||
158 | /* pull the callout info into kernel space */ | 173 | /* pull the callout info into kernel space */ |
159 | callout_info = NULL; | 174 | callout_info = NULL; |
175 | callout_len = 0; | ||
160 | if (_callout_info) { | 176 | if (_callout_info) { |
161 | callout_info = strndup_user(_callout_info, PAGE_SIZE); | 177 | callout_info = strndup_user(_callout_info, PAGE_SIZE); |
162 | if (IS_ERR(callout_info)) { | 178 | if (IS_ERR(callout_info)) { |
163 | ret = PTR_ERR(callout_info); | 179 | ret = PTR_ERR(callout_info); |
164 | goto error2; | 180 | goto error2; |
165 | } | 181 | } |
182 | callout_len = strlen(callout_info); | ||
166 | } | 183 | } |
167 | 184 | ||
168 | /* get the destination keyring if specified */ | 185 | /* get the destination keyring if specified */ |
@@ -183,8 +200,8 @@ asmlinkage long sys_request_key(const char __user *_type, | |||
183 | } | 200 | } |
184 | 201 | ||
185 | /* do the search */ | 202 | /* do the search */ |
186 | key = request_key_and_link(ktype, description, callout_info, NULL, | 203 | key = request_key_and_link(ktype, description, callout_info, |
187 | key_ref_to_ptr(dest_ref), | 204 | callout_len, NULL, key_ref_to_ptr(dest_ref), |
188 | KEY_ALLOC_IN_QUOTA); | 205 | KEY_ALLOC_IN_QUOTA); |
189 | if (IS_ERR(key)) { | 206 | if (IS_ERR(key)) { |
190 | ret = PTR_ERR(key); | 207 | ret = PTR_ERR(key); |
@@ -714,10 +731,16 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
714 | 731 | ||
715 | /* transfer the quota burden to the new user */ | 732 | /* transfer the quota burden to the new user */ |
716 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 733 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
734 | unsigned maxkeys = (uid == 0) ? | ||
735 | key_quota_root_maxkeys : key_quota_maxkeys; | ||
736 | unsigned maxbytes = (uid == 0) ? | ||
737 | key_quota_root_maxbytes : key_quota_maxbytes; | ||
738 | |||
717 | spin_lock(&newowner->lock); | 739 | spin_lock(&newowner->lock); |
718 | if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || | 740 | if (newowner->qnkeys + 1 >= maxkeys || |
719 | newowner->qnbytes + key->quotalen >= | 741 | newowner->qnbytes + key->quotalen >= maxbytes || |
720 | KEYQUOTA_MAX_BYTES) | 742 | newowner->qnbytes + key->quotalen < |
743 | newowner->qnbytes) | ||
721 | goto quota_overrun; | 744 | goto quota_overrun; |
722 | 745 | ||
723 | newowner->qnkeys++; | 746 | newowner->qnkeys++; |
@@ -821,9 +844,10 @@ long keyctl_instantiate_key(key_serial_t id, | |||
821 | key_ref_t keyring_ref; | 844 | key_ref_t keyring_ref; |
822 | void *payload; | 845 | void *payload; |
823 | long ret; | 846 | long ret; |
847 | bool vm = false; | ||
824 | 848 | ||
825 | ret = -EINVAL; | 849 | ret = -EINVAL; |
826 | if (plen > 32767) | 850 | if (plen > 1024 * 1024 - 1) |
827 | goto error; | 851 | goto error; |
828 | 852 | ||
829 | /* the appropriate instantiation authorisation key must have been | 853 | /* the appropriate instantiation authorisation key must have been |
@@ -843,8 +867,14 @@ long keyctl_instantiate_key(key_serial_t id, | |||
843 | if (_payload) { | 867 | if (_payload) { |
844 | ret = -ENOMEM; | 868 | ret = -ENOMEM; |
845 | payload = kmalloc(plen, GFP_KERNEL); | 869 | payload = kmalloc(plen, GFP_KERNEL); |
846 | if (!payload) | 870 | if (!payload) { |
847 | goto error; | 871 | if (plen <= PAGE_SIZE) |
872 | goto error; | ||
873 | vm = true; | ||
874 | payload = vmalloc(plen); | ||
875 | if (!payload) | ||
876 | goto error; | ||
877 | } | ||
848 | 878 | ||
849 | ret = -EFAULT; | 879 | ret = -EFAULT; |
850 | if (copy_from_user(payload, _payload, plen) != 0) | 880 | if (copy_from_user(payload, _payload, plen) != 0) |
@@ -877,7 +907,10 @@ long keyctl_instantiate_key(key_serial_t id, | |||
877 | } | 907 | } |
878 | 908 | ||
879 | error2: | 909 | error2: |
880 | kfree(payload); | 910 | if (!vm) |
911 | kfree(payload); | ||
912 | else | ||
913 | vfree(payload); | ||
881 | error: | 914 | error: |
882 | return ret; | 915 | return ret; |
883 | 916 | ||
@@ -1055,6 +1088,66 @@ error: | |||
1055 | 1088 | ||
1056 | } /* end keyctl_assume_authority() */ | 1089 | } /* end keyctl_assume_authority() */ |
1057 | 1090 | ||
1091 | /* | ||
1092 | * get the security label of a key | ||
1093 | * - the key must grant us view permission | ||
1094 | * - if there's a buffer, we place up to buflen bytes of data into it | ||
1095 | * - unless there's an error, we return the amount of information available, | ||
1096 | * irrespective of how much we may have copied (including the terminal NUL) | ||
1097 | * - implements keyctl(KEYCTL_GET_SECURITY) | ||
1098 | */ | ||
1099 | long keyctl_get_security(key_serial_t keyid, | ||
1100 | char __user *buffer, | ||
1101 | size_t buflen) | ||
1102 | { | ||
1103 | struct key *key, *instkey; | ||
1104 | key_ref_t key_ref; | ||
1105 | char *context; | ||
1106 | long ret; | ||
1107 | |||
1108 | key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); | ||
1109 | if (IS_ERR(key_ref)) { | ||
1110 | if (PTR_ERR(key_ref) != -EACCES) | ||
1111 | return PTR_ERR(key_ref); | ||
1112 | |||
1113 | /* viewing a key under construction is also permitted if we | ||
1114 | * have the authorisation token handy */ | ||
1115 | instkey = key_get_instantiation_authkey(keyid); | ||
1116 | if (IS_ERR(instkey)) | ||
1117 | return PTR_ERR(key_ref); | ||
1118 | key_put(instkey); | ||
1119 | |||
1120 | key_ref = lookup_user_key(NULL, keyid, 0, 1, 0); | ||
1121 | if (IS_ERR(key_ref)) | ||
1122 | return PTR_ERR(key_ref); | ||
1123 | } | ||
1124 | |||
1125 | key = key_ref_to_ptr(key_ref); | ||
1126 | ret = security_key_getsecurity(key, &context); | ||
1127 | if (ret == 0) { | ||
1128 | /* if no information was returned, give userspace an empty | ||
1129 | * string */ | ||
1130 | ret = 1; | ||
1131 | if (buffer && buflen > 0 && | ||
1132 | copy_to_user(buffer, "", 1) != 0) | ||
1133 | ret = -EFAULT; | ||
1134 | } else if (ret > 0) { | ||
1135 | /* return as much data as there's room for */ | ||
1136 | if (buffer && buflen > 0) { | ||
1137 | if (buflen > ret) | ||
1138 | buflen = ret; | ||
1139 | |||
1140 | if (copy_to_user(buffer, context, buflen) != 0) | ||
1141 | ret = -EFAULT; | ||
1142 | } | ||
1143 | |||
1144 | kfree(context); | ||
1145 | } | ||
1146 | |||
1147 | key_ref_put(key_ref); | ||
1148 | return ret; | ||
1149 | } | ||
1150 | |||
1058 | /*****************************************************************************/ | 1151 | /*****************************************************************************/ |
1059 | /* | 1152 | /* |
1060 | * the key control system call | 1153 | * the key control system call |
@@ -1135,6 +1228,11 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | |||
1135 | case KEYCTL_ASSUME_AUTHORITY: | 1228 | case KEYCTL_ASSUME_AUTHORITY: |
1136 | return keyctl_assume_authority((key_serial_t) arg2); | 1229 | return keyctl_assume_authority((key_serial_t) arg2); |
1137 | 1230 | ||
1231 | case KEYCTL_GET_SECURITY: | ||
1232 | return keyctl_get_security((key_serial_t) arg2, | ||
1233 | (char *) arg3, | ||
1234 | (size_t) arg4); | ||
1235 | |||
1138 | default: | 1236 | default: |
1139 | return -EOPNOTSUPP; | 1237 | return -EOPNOTSUPP; |
1140 | } | 1238 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 88292e3dee96..a9ab8affc092 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* keyring.c: keyring handling | 1 | /* Keyring handling |
2 | * | 2 | * |
3 | * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -79,7 +79,7 @@ static DECLARE_RWSEM(keyring_serialise_link_sem); | |||
79 | * publish the name of a keyring so that it can be found by name (if it has | 79 | * publish the name of a keyring so that it can be found by name (if it has |
80 | * one) | 80 | * one) |
81 | */ | 81 | */ |
82 | void keyring_publish_name(struct key *keyring) | 82 | static void keyring_publish_name(struct key *keyring) |
83 | { | 83 | { |
84 | int bucket; | 84 | int bucket; |
85 | 85 | ||
@@ -292,7 +292,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
292 | 292 | ||
293 | struct keyring_list *keylist; | 293 | struct keyring_list *keylist; |
294 | struct timespec now; | 294 | struct timespec now; |
295 | unsigned long possessed; | 295 | unsigned long possessed, kflags; |
296 | struct key *keyring, *key; | 296 | struct key *keyring, *key; |
297 | key_ref_t key_ref; | 297 | key_ref_t key_ref; |
298 | long err; | 298 | long err; |
@@ -319,6 +319,32 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
319 | err = -EAGAIN; | 319 | err = -EAGAIN; |
320 | sp = 0; | 320 | sp = 0; |
321 | 321 | ||
322 | /* firstly we should check to see if this top-level keyring is what we | ||
323 | * are looking for */ | ||
324 | key_ref = ERR_PTR(-EAGAIN); | ||
325 | kflags = keyring->flags; | ||
326 | if (keyring->type == type && match(keyring, description)) { | ||
327 | key = keyring; | ||
328 | |||
329 | /* check it isn't negative and hasn't expired or been | ||
330 | * revoked */ | ||
331 | if (kflags & (1 << KEY_FLAG_REVOKED)) | ||
332 | goto error_2; | ||
333 | if (key->expiry && now.tv_sec >= key->expiry) | ||
334 | goto error_2; | ||
335 | key_ref = ERR_PTR(-ENOKEY); | ||
336 | if (kflags & (1 << KEY_FLAG_NEGATIVE)) | ||
337 | goto error_2; | ||
338 | goto found; | ||
339 | } | ||
340 | |||
341 | /* otherwise, the top keyring must not be revoked, expired, or | ||
342 | * negatively instantiated if we are to search it */ | ||
343 | key_ref = ERR_PTR(-EAGAIN); | ||
344 | if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || | ||
345 | (keyring->expiry && now.tv_sec >= keyring->expiry)) | ||
346 | goto error_2; | ||
347 | |||
322 | /* start processing a new keyring */ | 348 | /* start processing a new keyring */ |
323 | descend: | 349 | descend: |
324 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 350 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
@@ -331,13 +357,14 @@ descend: | |||
331 | /* iterate through the keys in this keyring first */ | 357 | /* iterate through the keys in this keyring first */ |
332 | for (kix = 0; kix < keylist->nkeys; kix++) { | 358 | for (kix = 0; kix < keylist->nkeys; kix++) { |
333 | key = keylist->keys[kix]; | 359 | key = keylist->keys[kix]; |
360 | kflags = key->flags; | ||
334 | 361 | ||
335 | /* ignore keys not of this type */ | 362 | /* ignore keys not of this type */ |
336 | if (key->type != type) | 363 | if (key->type != type) |
337 | continue; | 364 | continue; |
338 | 365 | ||
339 | /* skip revoked keys and expired keys */ | 366 | /* skip revoked keys and expired keys */ |
340 | if (test_bit(KEY_FLAG_REVOKED, &key->flags)) | 367 | if (kflags & (1 << KEY_FLAG_REVOKED)) |
341 | continue; | 368 | continue; |
342 | 369 | ||
343 | if (key->expiry && now.tv_sec >= key->expiry) | 370 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -352,8 +379,8 @@ descend: | |||
352 | context, KEY_SEARCH) < 0) | 379 | context, KEY_SEARCH) < 0) |
353 | continue; | 380 | continue; |
354 | 381 | ||
355 | /* we set a different error code if we find a negative key */ | 382 | /* we set a different error code if we pass a negative key */ |
356 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { | 383 | if (kflags & (1 << KEY_FLAG_NEGATIVE)) { |
357 | err = -ENOKEY; | 384 | err = -ENOKEY; |
358 | continue; | 385 | continue; |
359 | } | 386 | } |
@@ -489,10 +516,9 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
489 | /* | 516 | /* |
490 | * find a keyring with the specified name | 517 | * find a keyring with the specified name |
491 | * - all named keyrings are searched | 518 | * - all named keyrings are searched |
492 | * - only find keyrings with search permission for the process | 519 | * - normally only finds keyrings with search permission for the current process |
493 | * - only find keyrings with a serial number greater than the one specified | ||
494 | */ | 520 | */ |
495 | struct key *find_keyring_by_name(const char *name, key_serial_t bound) | 521 | struct key *find_keyring_by_name(const char *name, bool skip_perm_check) |
496 | { | 522 | { |
497 | struct key *keyring; | 523 | struct key *keyring; |
498 | int bucket; | 524 | int bucket; |
@@ -518,15 +544,11 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) | |||
518 | if (strcmp(keyring->description, name) != 0) | 544 | if (strcmp(keyring->description, name) != 0) |
519 | continue; | 545 | continue; |
520 | 546 | ||
521 | if (key_permission(make_key_ref(keyring, 0), | 547 | if (!skip_perm_check && |
548 | key_permission(make_key_ref(keyring, 0), | ||
522 | KEY_SEARCH) < 0) | 549 | KEY_SEARCH) < 0) |
523 | continue; | 550 | continue; |
524 | 551 | ||
525 | /* found a potential candidate, but we still need to | ||
526 | * check the serial number */ | ||
527 | if (keyring->serial <= bound) | ||
528 | continue; | ||
529 | |||
530 | /* we've got a match */ | 552 | /* we've got a match */ |
531 | atomic_inc(&keyring->usage); | 553 | atomic_inc(&keyring->usage); |
532 | read_unlock(&keyring_name_lock); | 554 | read_unlock(&keyring_name_lock); |
diff --git a/security/keys/proc.c b/security/keys/proc.c index 694126003ed3..f619170da760 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -70,19 +70,15 @@ static int __init key_proc_init(void) | |||
70 | struct proc_dir_entry *p; | 70 | struct proc_dir_entry *p; |
71 | 71 | ||
72 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS | 72 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS |
73 | p = create_proc_entry("keys", 0, NULL); | 73 | p = proc_create("keys", 0, NULL, &proc_keys_fops); |
74 | if (!p) | 74 | if (!p) |
75 | panic("Cannot create /proc/keys\n"); | 75 | panic("Cannot create /proc/keys\n"); |
76 | |||
77 | p->proc_fops = &proc_keys_fops; | ||
78 | #endif | 76 | #endif |
79 | 77 | ||
80 | p = create_proc_entry("key-users", 0, NULL); | 78 | p = proc_create("key-users", 0, NULL, &proc_key_users_fops); |
81 | if (!p) | 79 | if (!p) |
82 | panic("Cannot create /proc/key-users\n"); | 80 | panic("Cannot create /proc/key-users\n"); |
83 | 81 | ||
84 | p->proc_fops = &proc_key_users_fops; | ||
85 | |||
86 | return 0; | 82 | return 0; |
87 | 83 | ||
88 | } /* end key_proc_init() */ | 84 | } /* end key_proc_init() */ |
@@ -246,6 +242,10 @@ static int proc_key_users_show(struct seq_file *m, void *v) | |||
246 | { | 242 | { |
247 | struct rb_node *_p = v; | 243 | struct rb_node *_p = v; |
248 | struct key_user *user = rb_entry(_p, struct key_user, node); | 244 | struct key_user *user = rb_entry(_p, struct key_user, node); |
245 | unsigned maxkeys = (user->uid == 0) ? | ||
246 | key_quota_root_maxkeys : key_quota_maxkeys; | ||
247 | unsigned maxbytes = (user->uid == 0) ? | ||
248 | key_quota_root_maxbytes : key_quota_maxbytes; | ||
249 | 249 | ||
250 | seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", | 250 | seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", |
251 | user->uid, | 251 | user->uid, |
@@ -253,10 +253,9 @@ static int proc_key_users_show(struct seq_file *m, void *v) | |||
253 | atomic_read(&user->nkeys), | 253 | atomic_read(&user->nkeys), |
254 | atomic_read(&user->nikeys), | 254 | atomic_read(&user->nikeys), |
255 | user->qnkeys, | 255 | user->qnkeys, |
256 | KEYQUOTA_MAX_KEYS, | 256 | maxkeys, |
257 | user->qnbytes, | 257 | user->qnbytes, |
258 | KEYQUOTA_MAX_BYTES | 258 | maxbytes); |
259 | ); | ||
260 | 259 | ||
261 | return 0; | 260 | return 0; |
262 | 261 | ||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index c886a2bb792a..5be6d018759a 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* process_keys.c: management of a process's keyrings | 1 | /* Management of a process's keyrings |
2 | * | 2 | * |
3 | * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -23,6 +23,9 @@ | |||
23 | /* session keyring create vs join semaphore */ | 23 | /* session keyring create vs join semaphore */ |
24 | static DEFINE_MUTEX(key_session_mutex); | 24 | static DEFINE_MUTEX(key_session_mutex); |
25 | 25 | ||
26 | /* user keyring creation semaphore */ | ||
27 | static DEFINE_MUTEX(key_user_keyring_mutex); | ||
28 | |||
26 | /* the root user's tracking struct */ | 29 | /* the root user's tracking struct */ |
27 | struct key_user root_key_user = { | 30 | struct key_user root_key_user = { |
28 | .usage = ATOMIC_INIT(3), | 31 | .usage = ATOMIC_INIT(3), |
@@ -33,78 +36,84 @@ struct key_user root_key_user = { | |||
33 | .uid = 0, | 36 | .uid = 0, |
34 | }; | 37 | }; |
35 | 38 | ||
36 | /* the root user's UID keyring */ | ||
37 | struct key root_user_keyring = { | ||
38 | .usage = ATOMIC_INIT(1), | ||
39 | .serial = 2, | ||
40 | .type = &key_type_keyring, | ||
41 | .user = &root_key_user, | ||
42 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), | ||
43 | .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | ||
44 | .flags = 1 << KEY_FLAG_INSTANTIATED, | ||
45 | .description = "_uid.0", | ||
46 | #ifdef KEY_DEBUGGING | ||
47 | .magic = KEY_DEBUG_MAGIC, | ||
48 | #endif | ||
49 | }; | ||
50 | |||
51 | /* the root user's default session keyring */ | ||
52 | struct key root_session_keyring = { | ||
53 | .usage = ATOMIC_INIT(1), | ||
54 | .serial = 1, | ||
55 | .type = &key_type_keyring, | ||
56 | .user = &root_key_user, | ||
57 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), | ||
58 | .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | ||
59 | .flags = 1 << KEY_FLAG_INSTANTIATED, | ||
60 | .description = "_uid_ses.0", | ||
61 | #ifdef KEY_DEBUGGING | ||
62 | .magic = KEY_DEBUG_MAGIC, | ||
63 | #endif | ||
64 | }; | ||
65 | |||
66 | /*****************************************************************************/ | 39 | /*****************************************************************************/ |
67 | /* | 40 | /* |
68 | * allocate the keyrings to be associated with a UID | 41 | * install user and user session keyrings for a particular UID |
69 | */ | 42 | */ |
70 | int alloc_uid_keyring(struct user_struct *user, | 43 | static int install_user_keyrings(struct task_struct *tsk) |
71 | struct task_struct *ctx) | ||
72 | { | 44 | { |
45 | struct user_struct *user = tsk->user; | ||
73 | struct key *uid_keyring, *session_keyring; | 46 | struct key *uid_keyring, *session_keyring; |
74 | char buf[20]; | 47 | char buf[20]; |
75 | int ret; | 48 | int ret; |
76 | 49 | ||
77 | /* concoct a default session keyring */ | 50 | kenter("%p{%u}", user, user->uid); |
78 | sprintf(buf, "_uid_ses.%u", user->uid); | ||
79 | 51 | ||
80 | session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, | 52 | if (user->uid_keyring) { |
81 | KEY_ALLOC_IN_QUOTA, NULL); | 53 | kleave(" = 0 [exist]"); |
82 | if (IS_ERR(session_keyring)) { | 54 | return 0; |
83 | ret = PTR_ERR(session_keyring); | ||
84 | goto error; | ||
85 | } | 55 | } |
86 | 56 | ||
87 | /* and a UID specific keyring, pointed to by the default session | 57 | mutex_lock(&key_user_keyring_mutex); |
88 | * keyring */ | 58 | ret = 0; |
89 | sprintf(buf, "_uid.%u", user->uid); | ||
90 | 59 | ||
91 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, | 60 | if (!user->uid_keyring) { |
92 | KEY_ALLOC_IN_QUOTA, session_keyring); | 61 | /* get the UID-specific keyring |
93 | if (IS_ERR(uid_keyring)) { | 62 | * - there may be one in existence already as it may have been |
94 | key_put(session_keyring); | 63 | * pinned by a session, but the user_struct pointing to it |
95 | ret = PTR_ERR(uid_keyring); | 64 | * may have been destroyed by setuid */ |
96 | goto error; | 65 | sprintf(buf, "_uid.%u", user->uid); |
66 | |||
67 | uid_keyring = find_keyring_by_name(buf, true); | ||
68 | if (IS_ERR(uid_keyring)) { | ||
69 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, | ||
70 | tsk, KEY_ALLOC_IN_QUOTA, | ||
71 | NULL); | ||
72 | if (IS_ERR(uid_keyring)) { | ||
73 | ret = PTR_ERR(uid_keyring); | ||
74 | goto error; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /* get a default session keyring (which might also exist | ||
79 | * already) */ | ||
80 | sprintf(buf, "_uid_ses.%u", user->uid); | ||
81 | |||
82 | session_keyring = find_keyring_by_name(buf, true); | ||
83 | if (IS_ERR(session_keyring)) { | ||
84 | session_keyring = | ||
85 | keyring_alloc(buf, user->uid, (gid_t) -1, | ||
86 | tsk, KEY_ALLOC_IN_QUOTA, NULL); | ||
87 | if (IS_ERR(session_keyring)) { | ||
88 | ret = PTR_ERR(session_keyring); | ||
89 | goto error_release; | ||
90 | } | ||
91 | |||
92 | /* we install a link from the user session keyring to | ||
93 | * the user keyring */ | ||
94 | ret = key_link(session_keyring, uid_keyring); | ||
95 | if (ret < 0) | ||
96 | goto error_release_both; | ||
97 | } | ||
98 | |||
99 | /* install the keyrings */ | ||
100 | user->uid_keyring = uid_keyring; | ||
101 | user->session_keyring = session_keyring; | ||
97 | } | 102 | } |
98 | 103 | ||
99 | /* install the keyrings */ | 104 | mutex_unlock(&key_user_keyring_mutex); |
100 | user->uid_keyring = uid_keyring; | 105 | kleave(" = 0"); |
101 | user->session_keyring = session_keyring; | 106 | return 0; |
102 | ret = 0; | ||
103 | 107 | ||
108 | error_release_both: | ||
109 | key_put(session_keyring); | ||
110 | error_release: | ||
111 | key_put(uid_keyring); | ||
104 | error: | 112 | error: |
113 | mutex_unlock(&key_user_keyring_mutex); | ||
114 | kleave(" = %d", ret); | ||
105 | return ret; | 115 | return ret; |
106 | 116 | } | |
107 | } /* end alloc_uid_keyring() */ | ||
108 | 117 | ||
109 | /*****************************************************************************/ | 118 | /*****************************************************************************/ |
110 | /* | 119 | /* |
@@ -481,7 +490,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
481 | } | 490 | } |
482 | } | 491 | } |
483 | /* or search the user-session keyring */ | 492 | /* or search the user-session keyring */ |
484 | else { | 493 | else if (context->user->session_keyring) { |
485 | key_ref = keyring_search_aux( | 494 | key_ref = keyring_search_aux( |
486 | make_key_ref(context->user->session_keyring, 1), | 495 | make_key_ref(context->user->session_keyring, 1), |
487 | context, type, description, match); | 496 | context, type, description, match); |
@@ -614,6 +623,9 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, | |||
614 | if (!context->signal->session_keyring) { | 623 | if (!context->signal->session_keyring) { |
615 | /* always install a session keyring upon access if one | 624 | /* always install a session keyring upon access if one |
616 | * doesn't exist yet */ | 625 | * doesn't exist yet */ |
626 | ret = install_user_keyrings(context); | ||
627 | if (ret < 0) | ||
628 | goto error; | ||
617 | ret = install_session_keyring( | 629 | ret = install_session_keyring( |
618 | context, context->user->session_keyring); | 630 | context, context->user->session_keyring); |
619 | if (ret < 0) | 631 | if (ret < 0) |
@@ -628,12 +640,24 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, | |||
628 | break; | 640 | break; |
629 | 641 | ||
630 | case KEY_SPEC_USER_KEYRING: | 642 | case KEY_SPEC_USER_KEYRING: |
643 | if (!context->user->uid_keyring) { | ||
644 | ret = install_user_keyrings(context); | ||
645 | if (ret < 0) | ||
646 | goto error; | ||
647 | } | ||
648 | |||
631 | key = context->user->uid_keyring; | 649 | key = context->user->uid_keyring; |
632 | atomic_inc(&key->usage); | 650 | atomic_inc(&key->usage); |
633 | key_ref = make_key_ref(key, 1); | 651 | key_ref = make_key_ref(key, 1); |
634 | break; | 652 | break; |
635 | 653 | ||
636 | case KEY_SPEC_USER_SESSION_KEYRING: | 654 | case KEY_SPEC_USER_SESSION_KEYRING: |
655 | if (!context->user->session_keyring) { | ||
656 | ret = install_user_keyrings(context); | ||
657 | if (ret < 0) | ||
658 | goto error; | ||
659 | } | ||
660 | |||
637 | key = context->user->session_keyring; | 661 | key = context->user->session_keyring; |
638 | atomic_inc(&key->usage); | 662 | atomic_inc(&key->usage); |
639 | key_ref = make_key_ref(key, 1); | 663 | key_ref = make_key_ref(key, 1); |
@@ -744,7 +768,7 @@ long join_session_keyring(const char *name) | |||
744 | mutex_lock(&key_session_mutex); | 768 | mutex_lock(&key_session_mutex); |
745 | 769 | ||
746 | /* look for an existing keyring of this name */ | 770 | /* look for an existing keyring of this name */ |
747 | keyring = find_keyring_by_name(name, 0); | 771 | keyring = find_keyring_by_name(name, false); |
748 | if (PTR_ERR(keyring) == -ENOKEY) { | 772 | if (PTR_ERR(keyring) == -ENOKEY) { |
749 | /* not found - try and create a new one */ | 773 | /* not found - try and create a new one */ |
750 | keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, | 774 | keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 5ecc5057fb54..ba32ca6469bd 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/kmod.h> | 16 | #include <linux/kmod.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/keyctl.h> | 18 | #include <linux/keyctl.h> |
19 | #include <linux/slab.h> | ||
19 | #include "internal.h" | 20 | #include "internal.h" |
20 | 21 | ||
21 | /* | 22 | /* |
@@ -161,21 +162,22 @@ error_alloc: | |||
161 | * call out to userspace for key construction | 162 | * call out to userspace for key construction |
162 | * - we ignore program failure and go on key status instead | 163 | * - we ignore program failure and go on key status instead |
163 | */ | 164 | */ |
164 | static int construct_key(struct key *key, const char *callout_info, void *aux) | 165 | static int construct_key(struct key *key, const void *callout_info, |
166 | size_t callout_len, void *aux) | ||
165 | { | 167 | { |
166 | struct key_construction *cons; | 168 | struct key_construction *cons; |
167 | request_key_actor_t actor; | 169 | request_key_actor_t actor; |
168 | struct key *authkey; | 170 | struct key *authkey; |
169 | int ret; | 171 | int ret; |
170 | 172 | ||
171 | kenter("%d,%s,%p", key->serial, callout_info, aux); | 173 | kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux); |
172 | 174 | ||
173 | cons = kmalloc(sizeof(*cons), GFP_KERNEL); | 175 | cons = kmalloc(sizeof(*cons), GFP_KERNEL); |
174 | if (!cons) | 176 | if (!cons) |
175 | return -ENOMEM; | 177 | return -ENOMEM; |
176 | 178 | ||
177 | /* allocate an authorisation key */ | 179 | /* allocate an authorisation key */ |
178 | authkey = request_key_auth_new(key, callout_info); | 180 | authkey = request_key_auth_new(key, callout_info, callout_len); |
179 | if (IS_ERR(authkey)) { | 181 | if (IS_ERR(authkey)) { |
180 | kfree(cons); | 182 | kfree(cons); |
181 | ret = PTR_ERR(authkey); | 183 | ret = PTR_ERR(authkey); |
@@ -331,6 +333,7 @@ alloc_failed: | |||
331 | static struct key *construct_key_and_link(struct key_type *type, | 333 | static struct key *construct_key_and_link(struct key_type *type, |
332 | const char *description, | 334 | const char *description, |
333 | const char *callout_info, | 335 | const char *callout_info, |
336 | size_t callout_len, | ||
334 | void *aux, | 337 | void *aux, |
335 | struct key *dest_keyring, | 338 | struct key *dest_keyring, |
336 | unsigned long flags) | 339 | unsigned long flags) |
@@ -348,7 +351,7 @@ static struct key *construct_key_and_link(struct key_type *type, | |||
348 | key_user_put(user); | 351 | key_user_put(user); |
349 | 352 | ||
350 | if (ret == 0) { | 353 | if (ret == 0) { |
351 | ret = construct_key(key, callout_info, aux); | 354 | ret = construct_key(key, callout_info, callout_len, aux); |
352 | if (ret < 0) | 355 | if (ret < 0) |
353 | goto construction_failed; | 356 | goto construction_failed; |
354 | } | 357 | } |
@@ -370,7 +373,8 @@ construction_failed: | |||
370 | */ | 373 | */ |
371 | struct key *request_key_and_link(struct key_type *type, | 374 | struct key *request_key_and_link(struct key_type *type, |
372 | const char *description, | 375 | const char *description, |
373 | const char *callout_info, | 376 | const void *callout_info, |
377 | size_t callout_len, | ||
374 | void *aux, | 378 | void *aux, |
375 | struct key *dest_keyring, | 379 | struct key *dest_keyring, |
376 | unsigned long flags) | 380 | unsigned long flags) |
@@ -378,8 +382,8 @@ struct key *request_key_and_link(struct key_type *type, | |||
378 | struct key *key; | 382 | struct key *key; |
379 | key_ref_t key_ref; | 383 | key_ref_t key_ref; |
380 | 384 | ||
381 | kenter("%s,%s,%s,%p,%p,%lx", | 385 | kenter("%s,%s,%p,%zu,%p,%p,%lx", |
382 | type->name, description, callout_info, aux, | 386 | type->name, description, callout_info, callout_len, aux, |
383 | dest_keyring, flags); | 387 | dest_keyring, flags); |
384 | 388 | ||
385 | /* search all the process keyrings for a key */ | 389 | /* search all the process keyrings for a key */ |
@@ -398,7 +402,8 @@ struct key *request_key_and_link(struct key_type *type, | |||
398 | goto error; | 402 | goto error; |
399 | 403 | ||
400 | key = construct_key_and_link(type, description, callout_info, | 404 | key = construct_key_and_link(type, description, callout_info, |
401 | aux, dest_keyring, flags); | 405 | callout_len, aux, dest_keyring, |
406 | flags); | ||
402 | } | 407 | } |
403 | 408 | ||
404 | error: | 409 | error: |
@@ -434,10 +439,13 @@ struct key *request_key(struct key_type *type, | |||
434 | const char *callout_info) | 439 | const char *callout_info) |
435 | { | 440 | { |
436 | struct key *key; | 441 | struct key *key; |
442 | size_t callout_len = 0; | ||
437 | int ret; | 443 | int ret; |
438 | 444 | ||
439 | key = request_key_and_link(type, description, callout_info, NULL, | 445 | if (callout_info) |
440 | NULL, KEY_ALLOC_IN_QUOTA); | 446 | callout_len = strlen(callout_info); |
447 | key = request_key_and_link(type, description, callout_info, callout_len, | ||
448 | NULL, NULL, KEY_ALLOC_IN_QUOTA); | ||
441 | if (!IS_ERR(key)) { | 449 | if (!IS_ERR(key)) { |
442 | ret = wait_for_key_construction(key, false); | 450 | ret = wait_for_key_construction(key, false); |
443 | if (ret < 0) { | 451 | if (ret < 0) { |
@@ -458,14 +466,15 @@ EXPORT_SYMBOL(request_key); | |||
458 | */ | 466 | */ |
459 | struct key *request_key_with_auxdata(struct key_type *type, | 467 | struct key *request_key_with_auxdata(struct key_type *type, |
460 | const char *description, | 468 | const char *description, |
461 | const char *callout_info, | 469 | const void *callout_info, |
470 | size_t callout_len, | ||
462 | void *aux) | 471 | void *aux) |
463 | { | 472 | { |
464 | struct key *key; | 473 | struct key *key; |
465 | int ret; | 474 | int ret; |
466 | 475 | ||
467 | key = request_key_and_link(type, description, callout_info, aux, | 476 | key = request_key_and_link(type, description, callout_info, callout_len, |
468 | NULL, KEY_ALLOC_IN_QUOTA); | 477 | aux, NULL, KEY_ALLOC_IN_QUOTA); |
469 | if (!IS_ERR(key)) { | 478 | if (!IS_ERR(key)) { |
470 | ret = wait_for_key_construction(key, false); | 479 | ret = wait_for_key_construction(key, false); |
471 | if (ret < 0) { | 480 | if (ret < 0) { |
@@ -485,10 +494,12 @@ EXPORT_SYMBOL(request_key_with_auxdata); | |||
485 | */ | 494 | */ |
486 | struct key *request_key_async(struct key_type *type, | 495 | struct key *request_key_async(struct key_type *type, |
487 | const char *description, | 496 | const char *description, |
488 | const char *callout_info) | 497 | const void *callout_info, |
498 | size_t callout_len) | ||
489 | { | 499 | { |
490 | return request_key_and_link(type, description, callout_info, NULL, | 500 | return request_key_and_link(type, description, callout_info, |
491 | NULL, KEY_ALLOC_IN_QUOTA); | 501 | callout_len, NULL, NULL, |
502 | KEY_ALLOC_IN_QUOTA); | ||
492 | } | 503 | } |
493 | EXPORT_SYMBOL(request_key_async); | 504 | EXPORT_SYMBOL(request_key_async); |
494 | 505 | ||
@@ -500,10 +511,11 @@ EXPORT_SYMBOL(request_key_async); | |||
500 | */ | 511 | */ |
501 | struct key *request_key_async_with_auxdata(struct key_type *type, | 512 | struct key *request_key_async_with_auxdata(struct key_type *type, |
502 | const char *description, | 513 | const char *description, |
503 | const char *callout_info, | 514 | const void *callout_info, |
515 | size_t callout_len, | ||
504 | void *aux) | 516 | void *aux) |
505 | { | 517 | { |
506 | return request_key_and_link(type, description, callout_info, aux, | 518 | return request_key_and_link(type, description, callout_info, |
507 | NULL, KEY_ALLOC_IN_QUOTA); | 519 | callout_len, aux, NULL, KEY_ALLOC_IN_QUOTA); |
508 | } | 520 | } |
509 | EXPORT_SYMBOL(request_key_async_with_auxdata); | 521 | EXPORT_SYMBOL(request_key_async_with_auxdata); |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index e42b5252486f..bd237b0a6331 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/seq_file.h> | 17 | #include <linux/seq_file.h> |
18 | #include <linux/slab.h> | ||
18 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
19 | #include "internal.h" | 20 | #include "internal.h" |
20 | 21 | ||
@@ -61,7 +62,7 @@ static void request_key_auth_describe(const struct key *key, | |||
61 | 62 | ||
62 | seq_puts(m, "key:"); | 63 | seq_puts(m, "key:"); |
63 | seq_puts(m, key->description); | 64 | seq_puts(m, key->description); |
64 | seq_printf(m, " pid:%d ci:%zu", rka->pid, strlen(rka->callout_info)); | 65 | seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); |
65 | 66 | ||
66 | } /* end request_key_auth_describe() */ | 67 | } /* end request_key_auth_describe() */ |
67 | 68 | ||
@@ -77,7 +78,7 @@ static long request_key_auth_read(const struct key *key, | |||
77 | size_t datalen; | 78 | size_t datalen; |
78 | long ret; | 79 | long ret; |
79 | 80 | ||
80 | datalen = strlen(rka->callout_info); | 81 | datalen = rka->callout_len; |
81 | ret = datalen; | 82 | ret = datalen; |
82 | 83 | ||
83 | /* we can return the data as is */ | 84 | /* we can return the data as is */ |
@@ -137,7 +138,8 @@ static void request_key_auth_destroy(struct key *key) | |||
137 | * create an authorisation token for /sbin/request-key or whoever to gain | 138 | * create an authorisation token for /sbin/request-key or whoever to gain |
138 | * access to the caller's security data | 139 | * access to the caller's security data |
139 | */ | 140 | */ |
140 | struct key *request_key_auth_new(struct key *target, const char *callout_info) | 141 | struct key *request_key_auth_new(struct key *target, const void *callout_info, |
142 | size_t callout_len) | ||
141 | { | 143 | { |
142 | struct request_key_auth *rka, *irka; | 144 | struct request_key_auth *rka, *irka; |
143 | struct key *authkey = NULL; | 145 | struct key *authkey = NULL; |
@@ -152,7 +154,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
152 | kleave(" = -ENOMEM"); | 154 | kleave(" = -ENOMEM"); |
153 | return ERR_PTR(-ENOMEM); | 155 | return ERR_PTR(-ENOMEM); |
154 | } | 156 | } |
155 | rka->callout_info = kmalloc(strlen(callout_info) + 1, GFP_KERNEL); | 157 | rka->callout_info = kmalloc(callout_len, GFP_KERNEL); |
156 | if (!rka->callout_info) { | 158 | if (!rka->callout_info) { |
157 | kleave(" = -ENOMEM"); | 159 | kleave(" = -ENOMEM"); |
158 | kfree(rka); | 160 | kfree(rka); |
@@ -186,7 +188,8 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
186 | } | 188 | } |
187 | 189 | ||
188 | rka->target_key = key_get(target); | 190 | rka->target_key = key_get(target); |
189 | strcpy(rka->callout_info, callout_info); | 191 | memcpy(rka->callout_info, callout_info, callout_len); |
192 | rka->callout_len = callout_len; | ||
190 | 193 | ||
191 | /* allocate the auth key */ | 194 | /* allocate the auth key */ |
192 | sprintf(desc, "%x", target->serial); | 195 | sprintf(desc, "%x", target->serial); |
diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c new file mode 100644 index 000000000000..b611d493c2d8 --- /dev/null +++ b/security/keys/sysctl.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* Key management controls | ||
2 | * | ||
3 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/key.h> | ||
13 | #include <linux/sysctl.h> | ||
14 | #include "internal.h" | ||
15 | |||
16 | ctl_table key_sysctls[] = { | ||
17 | { | ||
18 | .ctl_name = CTL_UNNUMBERED, | ||
19 | .procname = "maxkeys", | ||
20 | .data = &key_quota_maxkeys, | ||
21 | .maxlen = sizeof(unsigned), | ||
22 | .mode = 0644, | ||
23 | .proc_handler = &proc_dointvec, | ||
24 | }, | ||
25 | { | ||
26 | .ctl_name = CTL_UNNUMBERED, | ||
27 | .procname = "maxbytes", | ||
28 | .data = &key_quota_maxbytes, | ||
29 | .maxlen = sizeof(unsigned), | ||
30 | .mode = 0644, | ||
31 | .proc_handler = &proc_dointvec, | ||
32 | }, | ||
33 | { | ||
34 | .ctl_name = CTL_UNNUMBERED, | ||
35 | .procname = "root_maxkeys", | ||
36 | .data = &key_quota_root_maxkeys, | ||
37 | .maxlen = sizeof(unsigned), | ||
38 | .mode = 0644, | ||
39 | .proc_handler = &proc_dointvec, | ||
40 | }, | ||
41 | { | ||
42 | .ctl_name = CTL_UNNUMBERED, | ||
43 | .procname = "root_maxbytes", | ||
44 | .data = &key_quota_root_maxbytes, | ||
45 | .maxlen = sizeof(unsigned), | ||
46 | .mode = 0644, | ||
47 | .proc_handler = &proc_dointvec, | ||
48 | }, | ||
49 | { .ctl_name = 0 } | ||
50 | }; | ||
diff --git a/security/security.c b/security/security.c index d5cb5898d967..59838a99b80e 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -491,23 +491,23 @@ void security_inode_delete(struct inode *inode) | |||
491 | security_ops->inode_delete(inode); | 491 | security_ops->inode_delete(inode); |
492 | } | 492 | } |
493 | 493 | ||
494 | int security_inode_setxattr(struct dentry *dentry, char *name, | 494 | int security_inode_setxattr(struct dentry *dentry, const char *name, |
495 | void *value, size_t size, int flags) | 495 | const void *value, size_t size, int flags) |
496 | { | 496 | { |
497 | if (unlikely(IS_PRIVATE(dentry->d_inode))) | 497 | if (unlikely(IS_PRIVATE(dentry->d_inode))) |
498 | return 0; | 498 | return 0; |
499 | return security_ops->inode_setxattr(dentry, name, value, size, flags); | 499 | return security_ops->inode_setxattr(dentry, name, value, size, flags); |
500 | } | 500 | } |
501 | 501 | ||
502 | void security_inode_post_setxattr(struct dentry *dentry, char *name, | 502 | void security_inode_post_setxattr(struct dentry *dentry, const char *name, |
503 | void *value, size_t size, int flags) | 503 | const void *value, size_t size, int flags) |
504 | { | 504 | { |
505 | if (unlikely(IS_PRIVATE(dentry->d_inode))) | 505 | if (unlikely(IS_PRIVATE(dentry->d_inode))) |
506 | return; | 506 | return; |
507 | security_ops->inode_post_setxattr(dentry, name, value, size, flags); | 507 | security_ops->inode_post_setxattr(dentry, name, value, size, flags); |
508 | } | 508 | } |
509 | 509 | ||
510 | int security_inode_getxattr(struct dentry *dentry, char *name) | 510 | int security_inode_getxattr(struct dentry *dentry, const char *name) |
511 | { | 511 | { |
512 | if (unlikely(IS_PRIVATE(dentry->d_inode))) | 512 | if (unlikely(IS_PRIVATE(dentry->d_inode))) |
513 | return 0; | 513 | return 0; |
@@ -521,7 +521,7 @@ int security_inode_listxattr(struct dentry *dentry) | |||
521 | return security_ops->inode_listxattr(dentry); | 521 | return security_ops->inode_listxattr(dentry); |
522 | } | 522 | } |
523 | 523 | ||
524 | int security_inode_removexattr(struct dentry *dentry, char *name) | 524 | int security_inode_removexattr(struct dentry *dentry, const char *name) |
525 | { | 525 | { |
526 | if (unlikely(IS_PRIVATE(dentry->d_inode))) | 526 | if (unlikely(IS_PRIVATE(dentry->d_inode))) |
527 | return 0; | 527 | return 0; |
@@ -886,7 +886,7 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | |||
886 | } | 886 | } |
887 | EXPORT_SYMBOL(security_secid_to_secctx); | 887 | EXPORT_SYMBOL(security_secid_to_secctx); |
888 | 888 | ||
889 | int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid) | 889 | int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) |
890 | { | 890 | { |
891 | return security_ops->secctx_to_secid(secdata, seclen, secid); | 891 | return security_ops->secctx_to_secid(secdata, seclen, secid); |
892 | } | 892 | } |
@@ -1156,6 +1156,11 @@ int security_key_permission(key_ref_t key_ref, | |||
1156 | return security_ops->key_permission(key_ref, context, perm); | 1156 | return security_ops->key_permission(key_ref, context, perm); |
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | int security_key_getsecurity(struct key *key, char **_buffer) | ||
1160 | { | ||
1161 | return security_ops->key_getsecurity(key, _buffer); | ||
1162 | } | ||
1163 | |||
1159 | #endif /* CONFIG_KEYS */ | 1164 | #endif /* CONFIG_KEYS */ |
1160 | 1165 | ||
1161 | #ifdef CONFIG_AUDIT | 1166 | #ifdef CONFIG_AUDIT |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 95a8ef4a5073..114b4b4c97b2 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -646,7 +646,7 @@ void avc_audit(u32 ssid, u32 tsid, | |||
646 | if (*p) | 646 | if (*p) |
647 | audit_log_untrustedstring(ab, p); | 647 | audit_log_untrustedstring(ab, p); |
648 | else | 648 | else |
649 | audit_log_hex(ab, p, len); | 649 | audit_log_n_hex(ab, p, len); |
650 | break; | 650 | break; |
651 | } | 651 | } |
652 | } | 652 | } |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 04acb5af8317..1c864c0efe2b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/spinlock.h> | 39 | #include <linux/spinlock.h> |
40 | #include <linux/syscalls.h> | 40 | #include <linux/syscalls.h> |
41 | #include <linux/file.h> | 41 | #include <linux/file.h> |
42 | #include <linux/fdtable.h> | ||
42 | #include <linux/namei.h> | 43 | #include <linux/namei.h> |
43 | #include <linux/mount.h> | 44 | #include <linux/mount.h> |
44 | #include <linux/ext2_fs.h> | 45 | #include <linux/ext2_fs.h> |
@@ -2619,7 +2620,7 @@ static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
2619 | return dentry_has_perm(current, mnt, dentry, FILE__GETATTR); | 2620 | return dentry_has_perm(current, mnt, dentry, FILE__GETATTR); |
2620 | } | 2621 | } |
2621 | 2622 | ||
2622 | static int selinux_inode_setotherxattr(struct dentry *dentry, char *name) | 2623 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) |
2623 | { | 2624 | { |
2624 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 2625 | if (!strncmp(name, XATTR_SECURITY_PREFIX, |
2625 | sizeof XATTR_SECURITY_PREFIX - 1)) { | 2626 | sizeof XATTR_SECURITY_PREFIX - 1)) { |
@@ -2638,7 +2639,8 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, char *name) | |||
2638 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); | 2639 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); |
2639 | } | 2640 | } |
2640 | 2641 | ||
2641 | static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags) | 2642 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, |
2643 | const void *value, size_t size, int flags) | ||
2642 | { | 2644 | { |
2643 | struct task_security_struct *tsec = current->security; | 2645 | struct task_security_struct *tsec = current->security; |
2644 | struct inode *inode = dentry->d_inode; | 2646 | struct inode *inode = dentry->d_inode; |
@@ -2687,8 +2689,9 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value | |||
2687 | &ad); | 2689 | &ad); |
2688 | } | 2690 | } |
2689 | 2691 | ||
2690 | static void selinux_inode_post_setxattr(struct dentry *dentry, char *name, | 2692 | static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, |
2691 | void *value, size_t size, int flags) | 2693 | const void *value, size_t size, |
2694 | int flags) | ||
2692 | { | 2695 | { |
2693 | struct inode *inode = dentry->d_inode; | 2696 | struct inode *inode = dentry->d_inode; |
2694 | struct inode_security_struct *isec = inode->i_security; | 2697 | struct inode_security_struct *isec = inode->i_security; |
@@ -2711,7 +2714,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name, | |||
2711 | return; | 2714 | return; |
2712 | } | 2715 | } |
2713 | 2716 | ||
2714 | static int selinux_inode_getxattr(struct dentry *dentry, char *name) | 2717 | static int selinux_inode_getxattr(struct dentry *dentry, const char *name) |
2715 | { | 2718 | { |
2716 | return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); | 2719 | return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); |
2717 | } | 2720 | } |
@@ -2721,7 +2724,7 @@ static int selinux_inode_listxattr(struct dentry *dentry) | |||
2721 | return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); | 2724 | return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); |
2722 | } | 2725 | } |
2723 | 2726 | ||
2724 | static int selinux_inode_removexattr(struct dentry *dentry, char *name) | 2727 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) |
2725 | { | 2728 | { |
2726 | if (strcmp(name, XATTR_NAME_SELINUX)) | 2729 | if (strcmp(name, XATTR_NAME_SELINUX)) |
2727 | return selinux_inode_setotherxattr(dentry, name); | 2730 | return selinux_inode_setotherxattr(dentry, name); |
@@ -3284,9 +3287,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, | |||
3284 | if (rc) | 3287 | if (rc) |
3285 | return rc; | 3288 | return rc; |
3286 | 3289 | ||
3287 | if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info))) | ||
3288 | return 0; | ||
3289 | |||
3290 | if (!sig) | 3290 | if (!sig) |
3291 | perm = PROCESS__SIGNULL; /* null signal; existence test */ | 3291 | perm = PROCESS__SIGNULL; /* null signal; existence test */ |
3292 | else | 3292 | else |
@@ -5236,7 +5236,7 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | |||
5236 | return security_sid_to_context(secid, secdata, seclen); | 5236 | return security_sid_to_context(secid, secdata, seclen); |
5237 | } | 5237 | } |
5238 | 5238 | ||
5239 | static int selinux_secctx_to_secid(char *secdata, u32 seclen, u32 *secid) | 5239 | static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) |
5240 | { | 5240 | { |
5241 | return security_context_to_sid(secdata, seclen, secid); | 5241 | return security_context_to_sid(secdata, seclen, secid); |
5242 | } | 5242 | } |
@@ -5298,6 +5298,20 @@ static int selinux_key_permission(key_ref_t key_ref, | |||
5298 | SECCLASS_KEY, perm, NULL); | 5298 | SECCLASS_KEY, perm, NULL); |
5299 | } | 5299 | } |
5300 | 5300 | ||
5301 | static int selinux_key_getsecurity(struct key *key, char **_buffer) | ||
5302 | { | ||
5303 | struct key_security_struct *ksec = key->security; | ||
5304 | char *context = NULL; | ||
5305 | unsigned len; | ||
5306 | int rc; | ||
5307 | |||
5308 | rc = security_sid_to_context(ksec->sid, &context, &len); | ||
5309 | if (!rc) | ||
5310 | rc = len; | ||
5311 | *_buffer = context; | ||
5312 | return rc; | ||
5313 | } | ||
5314 | |||
5301 | #endif | 5315 | #endif |
5302 | 5316 | ||
5303 | static struct security_operations selinux_ops = { | 5317 | static struct security_operations selinux_ops = { |
@@ -5486,6 +5500,7 @@ static struct security_operations selinux_ops = { | |||
5486 | .key_alloc = selinux_key_alloc, | 5500 | .key_alloc = selinux_key_alloc, |
5487 | .key_free = selinux_key_free, | 5501 | .key_free = selinux_key_free, |
5488 | .key_permission = selinux_key_permission, | 5502 | .key_permission = selinux_key_permission, |
5503 | .key_getsecurity = selinux_key_getsecurity, | ||
5489 | #endif | 5504 | #endif |
5490 | 5505 | ||
5491 | #ifdef CONFIG_AUDIT | 5506 | #ifdef CONFIG_AUDIT |
@@ -5534,14 +5549,6 @@ static __init int selinux_init(void) | |||
5534 | else | 5549 | else |
5535 | printk(KERN_DEBUG "SELinux: Starting in permissive mode\n"); | 5550 | printk(KERN_DEBUG "SELinux: Starting in permissive mode\n"); |
5536 | 5551 | ||
5537 | #ifdef CONFIG_KEYS | ||
5538 | /* Add security information to initial keyrings */ | ||
5539 | selinux_key_alloc(&root_user_keyring, current, | ||
5540 | KEY_ALLOC_NOT_IN_QUOTA); | ||
5541 | selinux_key_alloc(&root_session_keyring, current, | ||
5542 | KEY_ALLOC_NOT_IN_QUOTA); | ||
5543 | #endif | ||
5544 | |||
5545 | return 0; | 5552 | return 0; |
5546 | } | 5553 | } |
5547 | 5554 | ||
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 6445b6440648..ad30ac4273d6 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -93,10 +93,10 @@ int security_change_sid(u32 ssid, u32 tsid, | |||
93 | int security_sid_to_context(u32 sid, char **scontext, | 93 | int security_sid_to_context(u32 sid, char **scontext, |
94 | u32 *scontext_len); | 94 | u32 *scontext_len); |
95 | 95 | ||
96 | int security_context_to_sid(char *scontext, u32 scontext_len, | 96 | int security_context_to_sid(const char *scontext, u32 scontext_len, |
97 | u32 *out_sid); | 97 | u32 *out_sid); |
98 | 98 | ||
99 | int security_context_to_sid_default(char *scontext, u32 scontext_len, | 99 | int security_context_to_sid_default(const char *scontext, u32 scontext_len, |
100 | u32 *out_sid, u32 def_sid, gfp_t gfp_flags); | 100 | u32 *out_sid, u32 def_sid, gfp_t gfp_flags); |
101 | 101 | ||
102 | int security_get_user_sids(u32 callsid, char *username, | 102 | int security_get_user_sids(u32 callsid, char *username, |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 2daaddbb301d..dcc2e1c4fd83 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -708,7 +708,7 @@ out: | |||
708 | 708 | ||
709 | } | 709 | } |
710 | 710 | ||
711 | static int security_context_to_sid_core(char *scontext, u32 scontext_len, | 711 | static int security_context_to_sid_core(const char *scontext, u32 scontext_len, |
712 | u32 *sid, u32 def_sid, gfp_t gfp_flags) | 712 | u32 *sid, u32 def_sid, gfp_t gfp_flags) |
713 | { | 713 | { |
714 | char *scontext2; | 714 | char *scontext2; |
@@ -835,7 +835,7 @@ out: | |||
835 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient | 835 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient |
836 | * memory is available, or 0 on success. | 836 | * memory is available, or 0 on success. |
837 | */ | 837 | */ |
838 | int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) | 838 | int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) |
839 | { | 839 | { |
840 | return security_context_to_sid_core(scontext, scontext_len, | 840 | return security_context_to_sid_core(scontext, scontext_len, |
841 | sid, SECSID_NULL, GFP_KERNEL); | 841 | sid, SECSID_NULL, GFP_KERNEL); |
@@ -858,8 +858,8 @@ int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) | |||
858 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient | 858 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient |
859 | * memory is available, or 0 on success. | 859 | * memory is available, or 0 on success. |
860 | */ | 860 | */ |
861 | int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, | 861 | int security_context_to_sid_default(const char *scontext, u32 scontext_len, |
862 | u32 def_sid, gfp_t gfp_flags) | 862 | u32 *sid, u32 def_sid, gfp_t gfp_flags) |
863 | { | 863 | { |
864 | return security_context_to_sid_core(scontext, scontext_len, | 864 | return security_context_to_sid_core(scontext, scontext_len, |
865 | sid, def_sid, gfp_flags); | 865 | sid, def_sid, gfp_flags); |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 77ec16a3b68b..b5c8f9237008 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/pipe_fs_i.h> | 26 | #include <linux/pipe_fs_i.h> |
27 | #include <net/netlabel.h> | 27 | #include <net/netlabel.h> |
28 | #include <net/cipso_ipv4.h> | 28 | #include <net/cipso_ipv4.h> |
29 | #include <linux/audit.h> | ||
29 | 30 | ||
30 | #include "smack.h" | 31 | #include "smack.h" |
31 | 32 | ||
@@ -574,8 +575,8 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
574 | * | 575 | * |
575 | * Returns 0 if access is permitted, an error code otherwise | 576 | * Returns 0 if access is permitted, an error code otherwise |
576 | */ | 577 | */ |
577 | static int smack_inode_setxattr(struct dentry *dentry, char *name, | 578 | static int smack_inode_setxattr(struct dentry *dentry, const char *name, |
578 | void *value, size_t size, int flags) | 579 | const void *value, size_t size, int flags) |
579 | { | 580 | { |
580 | int rc = 0; | 581 | int rc = 0; |
581 | 582 | ||
@@ -604,8 +605,8 @@ static int smack_inode_setxattr(struct dentry *dentry, char *name, | |||
604 | * Set the pointer in the inode blob to the entry found | 605 | * Set the pointer in the inode blob to the entry found |
605 | * in the master label list. | 606 | * in the master label list. |
606 | */ | 607 | */ |
607 | static void smack_inode_post_setxattr(struct dentry *dentry, char *name, | 608 | static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, |
608 | void *value, size_t size, int flags) | 609 | const void *value, size_t size, int flags) |
609 | { | 610 | { |
610 | struct inode_smack *isp; | 611 | struct inode_smack *isp; |
611 | char *nsp; | 612 | char *nsp; |
@@ -641,7 +642,7 @@ static void smack_inode_post_setxattr(struct dentry *dentry, char *name, | |||
641 | * | 642 | * |
642 | * Returns 0 if access is permitted, an error code otherwise | 643 | * Returns 0 if access is permitted, an error code otherwise |
643 | */ | 644 | */ |
644 | static int smack_inode_getxattr(struct dentry *dentry, char *name) | 645 | static int smack_inode_getxattr(struct dentry *dentry, const char *name) |
645 | { | 646 | { |
646 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ); | 647 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ); |
647 | } | 648 | } |
@@ -655,7 +656,7 @@ static int smack_inode_getxattr(struct dentry *dentry, char *name) | |||
655 | * | 656 | * |
656 | * Returns 0 if access is permitted, an error code otherwise | 657 | * Returns 0 if access is permitted, an error code otherwise |
657 | */ | 658 | */ |
658 | static int smack_inode_removexattr(struct dentry *dentry, char *name) | 659 | static int smack_inode_removexattr(struct dentry *dentry, const char *name) |
659 | { | 660 | { |
660 | int rc = 0; | 661 | int rc = 0; |
661 | 662 | ||
@@ -752,6 +753,18 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer, | |||
752 | return -EINVAL; | 753 | return -EINVAL; |
753 | } | 754 | } |
754 | 755 | ||
756 | /** | ||
757 | * smack_inode_getsecid - Extract inode's security id | ||
758 | * @inode: inode to extract the info from | ||
759 | * @secid: where result will be saved | ||
760 | */ | ||
761 | static void smack_inode_getsecid(const struct inode *inode, u32 *secid) | ||
762 | { | ||
763 | struct inode_smack *isp = inode->i_security; | ||
764 | |||
765 | *secid = smack_to_secid(isp->smk_inode); | ||
766 | } | ||
767 | |||
755 | /* | 768 | /* |
756 | * File Hooks | 769 | * File Hooks |
757 | */ | 770 | */ |
@@ -1118,15 +1131,6 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, | |||
1118 | int sig, u32 secid) | 1131 | int sig, u32 secid) |
1119 | { | 1132 | { |
1120 | /* | 1133 | /* |
1121 | * Special cases where signals really ought to go through | ||
1122 | * in spite of policy. Stephen Smalley suggests it may | ||
1123 | * make sense to change the caller so that it doesn't | ||
1124 | * bother with the LSM hook in these cases. | ||
1125 | */ | ||
1126 | if (info != SEND_SIG_NOINFO && | ||
1127 | (is_si_special(info) || SI_FROMKERNEL(info))) | ||
1128 | return 0; | ||
1129 | /* | ||
1130 | * Sending a signal requires that the sender | 1134 | * Sending a signal requires that the sender |
1131 | * can write the receiver. | 1135 | * can write the receiver. |
1132 | */ | 1136 | */ |
@@ -1805,6 +1809,18 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) | |||
1805 | return smk_curacc(isp, may); | 1809 | return smk_curacc(isp, may); |
1806 | } | 1810 | } |
1807 | 1811 | ||
1812 | /** | ||
1813 | * smack_ipc_getsecid - Extract smack security id | ||
1814 | * @ipcp: the object permissions | ||
1815 | * @secid: where result will be saved | ||
1816 | */ | ||
1817 | static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) | ||
1818 | { | ||
1819 | char *smack = ipp->security; | ||
1820 | |||
1821 | *secid = smack_to_secid(smack); | ||
1822 | } | ||
1823 | |||
1808 | /* module stacking operations */ | 1824 | /* module stacking operations */ |
1809 | 1825 | ||
1810 | /** | 1826 | /** |
@@ -2382,6 +2398,124 @@ static int smack_key_permission(key_ref_t key_ref, | |||
2382 | #endif /* CONFIG_KEYS */ | 2398 | #endif /* CONFIG_KEYS */ |
2383 | 2399 | ||
2384 | /* | 2400 | /* |
2401 | * Smack Audit hooks | ||
2402 | * | ||
2403 | * Audit requires a unique representation of each Smack specific | ||
2404 | * rule. This unique representation is used to distinguish the | ||
2405 | * object to be audited from remaining kernel objects and also | ||
2406 | * works as a glue between the audit hooks. | ||
2407 | * | ||
2408 | * Since repository entries are added but never deleted, we'll use | ||
2409 | * the smack_known label address related to the given audit rule as | ||
2410 | * the needed unique representation. This also better fits the smack | ||
2411 | * model where nearly everything is a label. | ||
2412 | */ | ||
2413 | #ifdef CONFIG_AUDIT | ||
2414 | |||
2415 | /** | ||
2416 | * smack_audit_rule_init - Initialize a smack audit rule | ||
2417 | * @field: audit rule fields given from user-space (audit.h) | ||
2418 | * @op: required testing operator (=, !=, >, <, ...) | ||
2419 | * @rulestr: smack label to be audited | ||
2420 | * @vrule: pointer to save our own audit rule representation | ||
2421 | * | ||
2422 | * Prepare to audit cases where (@field @op @rulestr) is true. | ||
2423 | * The label to be audited is created if necessay. | ||
2424 | */ | ||
2425 | static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) | ||
2426 | { | ||
2427 | char **rule = (char **)vrule; | ||
2428 | *rule = NULL; | ||
2429 | |||
2430 | if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) | ||
2431 | return -EINVAL; | ||
2432 | |||
2433 | if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL) | ||
2434 | return -EINVAL; | ||
2435 | |||
2436 | *rule = smk_import(rulestr, 0); | ||
2437 | |||
2438 | return 0; | ||
2439 | } | ||
2440 | |||
2441 | /** | ||
2442 | * smack_audit_rule_known - Distinguish Smack audit rules | ||
2443 | * @krule: rule of interest, in Audit kernel representation format | ||
2444 | * | ||
2445 | * This is used to filter Smack rules from remaining Audit ones. | ||
2446 | * If it's proved that this rule belongs to us, the | ||
2447 | * audit_rule_match hook will be called to do the final judgement. | ||
2448 | */ | ||
2449 | static int smack_audit_rule_known(struct audit_krule *krule) | ||
2450 | { | ||
2451 | struct audit_field *f; | ||
2452 | int i; | ||
2453 | |||
2454 | for (i = 0; i < krule->field_count; i++) { | ||
2455 | f = &krule->fields[i]; | ||
2456 | |||
2457 | if (f->type == AUDIT_SUBJ_USER || f->type == AUDIT_OBJ_USER) | ||
2458 | return 1; | ||
2459 | } | ||
2460 | |||
2461 | return 0; | ||
2462 | } | ||
2463 | |||
2464 | /** | ||
2465 | * smack_audit_rule_match - Audit given object ? | ||
2466 | * @secid: security id for identifying the object to test | ||
2467 | * @field: audit rule flags given from user-space | ||
2468 | * @op: required testing operator | ||
2469 | * @vrule: smack internal rule presentation | ||
2470 | * @actx: audit context associated with the check | ||
2471 | * | ||
2472 | * The core Audit hook. It's used to take the decision of | ||
2473 | * whether to audit or not to audit a given object. | ||
2474 | */ | ||
2475 | static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, | ||
2476 | struct audit_context *actx) | ||
2477 | { | ||
2478 | char *smack; | ||
2479 | char *rule = vrule; | ||
2480 | |||
2481 | if (!rule) { | ||
2482 | audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR, | ||
2483 | "Smack: missing rule\n"); | ||
2484 | return -ENOENT; | ||
2485 | } | ||
2486 | |||
2487 | if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) | ||
2488 | return 0; | ||
2489 | |||
2490 | smack = smack_from_secid(secid); | ||
2491 | |||
2492 | /* | ||
2493 | * No need to do string comparisons. If a match occurs, | ||
2494 | * both pointers will point to the same smack_known | ||
2495 | * label. | ||
2496 | */ | ||
2497 | if (op == AUDIT_EQUAL) | ||
2498 | return (rule == smack); | ||
2499 | if (op == AUDIT_NOT_EQUAL) | ||
2500 | return (rule != smack); | ||
2501 | |||
2502 | return 0; | ||
2503 | } | ||
2504 | |||
2505 | /** | ||
2506 | * smack_audit_rule_free - free smack rule representation | ||
2507 | * @vrule: rule to be freed. | ||
2508 | * | ||
2509 | * No memory was allocated. | ||
2510 | */ | ||
2511 | static void smack_audit_rule_free(void *vrule) | ||
2512 | { | ||
2513 | /* No-op */ | ||
2514 | } | ||
2515 | |||
2516 | #endif /* CONFIG_AUDIT */ | ||
2517 | |||
2518 | /* | ||
2385 | * smack_secid_to_secctx - return the smack label for a secid | 2519 | * smack_secid_to_secctx - return the smack label for a secid |
2386 | * @secid: incoming integer | 2520 | * @secid: incoming integer |
2387 | * @secdata: destination | 2521 | * @secdata: destination |
@@ -2406,7 +2540,7 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | |||
2406 | * | 2540 | * |
2407 | * Exists for audit and networking code. | 2541 | * Exists for audit and networking code. |
2408 | */ | 2542 | */ |
2409 | static int smack_secctx_to_secid(char *secdata, u32 seclen, u32 *secid) | 2543 | static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) |
2410 | { | 2544 | { |
2411 | *secid = smack_to_secid(secdata); | 2545 | *secid = smack_to_secid(secdata); |
2412 | return 0; | 2546 | return 0; |
@@ -2467,6 +2601,7 @@ struct security_operations smack_ops = { | |||
2467 | .inode_getsecurity = smack_inode_getsecurity, | 2601 | .inode_getsecurity = smack_inode_getsecurity, |
2468 | .inode_setsecurity = smack_inode_setsecurity, | 2602 | .inode_setsecurity = smack_inode_setsecurity, |
2469 | .inode_listsecurity = smack_inode_listsecurity, | 2603 | .inode_listsecurity = smack_inode_listsecurity, |
2604 | .inode_getsecid = smack_inode_getsecid, | ||
2470 | 2605 | ||
2471 | .file_permission = smack_file_permission, | 2606 | .file_permission = smack_file_permission, |
2472 | .file_alloc_security = smack_file_alloc_security, | 2607 | .file_alloc_security = smack_file_alloc_security, |
@@ -2498,6 +2633,7 @@ struct security_operations smack_ops = { | |||
2498 | .task_prctl = cap_task_prctl, | 2633 | .task_prctl = cap_task_prctl, |
2499 | 2634 | ||
2500 | .ipc_permission = smack_ipc_permission, | 2635 | .ipc_permission = smack_ipc_permission, |
2636 | .ipc_getsecid = smack_ipc_getsecid, | ||
2501 | 2637 | ||
2502 | .msg_msg_alloc_security = smack_msg_msg_alloc_security, | 2638 | .msg_msg_alloc_security = smack_msg_msg_alloc_security, |
2503 | .msg_msg_free_security = smack_msg_msg_free_security, | 2639 | .msg_msg_free_security = smack_msg_msg_free_security, |
@@ -2542,12 +2678,22 @@ struct security_operations smack_ops = { | |||
2542 | .sk_free_security = smack_sk_free_security, | 2678 | .sk_free_security = smack_sk_free_security, |
2543 | .sock_graft = smack_sock_graft, | 2679 | .sock_graft = smack_sock_graft, |
2544 | .inet_conn_request = smack_inet_conn_request, | 2680 | .inet_conn_request = smack_inet_conn_request, |
2681 | |||
2545 | /* key management security hooks */ | 2682 | /* key management security hooks */ |
2546 | #ifdef CONFIG_KEYS | 2683 | #ifdef CONFIG_KEYS |
2547 | .key_alloc = smack_key_alloc, | 2684 | .key_alloc = smack_key_alloc, |
2548 | .key_free = smack_key_free, | 2685 | .key_free = smack_key_free, |
2549 | .key_permission = smack_key_permission, | 2686 | .key_permission = smack_key_permission, |
2550 | #endif /* CONFIG_KEYS */ | 2687 | #endif /* CONFIG_KEYS */ |
2688 | |||
2689 | /* Audit hooks */ | ||
2690 | #ifdef CONFIG_AUDIT | ||
2691 | .audit_rule_init = smack_audit_rule_init, | ||
2692 | .audit_rule_known = smack_audit_rule_known, | ||
2693 | .audit_rule_match = smack_audit_rule_match, | ||
2694 | .audit_rule_free = smack_audit_rule_free, | ||
2695 | #endif /* CONFIG_AUDIT */ | ||
2696 | |||
2551 | .secid_to_secctx = smack_secid_to_secctx, | 2697 | .secid_to_secctx = smack_secid_to_secctx, |
2552 | .secctx_to_secid = smack_secctx_to_secid, | 2698 | .secctx_to_secid = smack_secctx_to_secid, |
2553 | .release_secctx = smack_release_secctx, | 2699 | .release_secctx = smack_release_secctx, |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index a5da5a8cfe9b..271a835fbbe3 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -324,6 +324,7 @@ static void smk_cipso_doi(void) | |||
324 | struct netlbl_audit audit_info; | 324 | struct netlbl_audit audit_info; |
325 | 325 | ||
326 | audit_info.loginuid = audit_get_loginuid(current); | 326 | audit_info.loginuid = audit_get_loginuid(current); |
327 | audit_info.sessionid = audit_get_sessionid(current); | ||
327 | audit_info.secid = smack_to_secid(current->security); | 328 | audit_info.secid = smack_to_secid(current->security); |
328 | 329 | ||
329 | rc = netlbl_cfg_map_del(NULL, &audit_info); | 330 | rc = netlbl_cfg_map_del(NULL, &audit_info); |
@@ -356,6 +357,7 @@ static void smk_unlbl_ambient(char *oldambient) | |||
356 | struct netlbl_audit audit_info; | 357 | struct netlbl_audit audit_info; |
357 | 358 | ||
358 | audit_info.loginuid = audit_get_loginuid(current); | 359 | audit_info.loginuid = audit_get_loginuid(current); |
360 | audit_info.sessionid = audit_get_sessionid(current); | ||
359 | audit_info.secid = smack_to_secid(current->security); | 361 | audit_info.secid = smack_to_secid(current->security); |
360 | 362 | ||
361 | if (oldambient != NULL) { | 363 | if (oldambient != NULL) { |