diff options
Diffstat (limited to 'security')
34 files changed, 1246 insertions, 379 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/capability.c b/security/capability.c index 2c6e06d18fab..38ac54e3aed1 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -44,6 +44,7 @@ static struct security_operations capability_ops = { | |||
44 | .task_setioprio = cap_task_setioprio, | 44 | .task_setioprio = cap_task_setioprio, |
45 | .task_setnice = cap_task_setnice, | 45 | .task_setnice = cap_task_setnice, |
46 | .task_post_setuid = cap_task_post_setuid, | 46 | .task_post_setuid = cap_task_post_setuid, |
47 | .task_prctl = cap_task_prctl, | ||
47 | .task_reparent_to_init = cap_task_reparent_to_init, | 48 | .task_reparent_to_init = cap_task_reparent_to_init, |
48 | 49 | ||
49 | .syslog = cap_syslog, | 50 | .syslog = cap_syslog, |
diff --git a/security/commoncap.c b/security/commoncap.c index 852905789caf..5edabc7542ae 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -24,11 +24,8 @@ | |||
24 | #include <linux/hugetlb.h> | 24 | #include <linux/hugetlb.h> |
25 | #include <linux/mount.h> | 25 | #include <linux/mount.h> |
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | 27 | #include <linux/prctl.h> | |
28 | /* Global security state */ | 28 | #include <linux/securebits.h> |
29 | |||
30 | unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */ | ||
31 | EXPORT_SYMBOL(securebits); | ||
32 | 29 | ||
33 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) | 30 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) |
34 | { | 31 | { |
@@ -368,7 +365,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
368 | 365 | ||
369 | /* AUD: Audit candidate if current->cap_effective is set */ | 366 | /* AUD: Audit candidate if current->cap_effective is set */ |
370 | 367 | ||
371 | current->keep_capabilities = 0; | 368 | current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); |
372 | } | 369 | } |
373 | 370 | ||
374 | int cap_bprm_secureexec (struct linux_binprm *bprm) | 371 | int cap_bprm_secureexec (struct linux_binprm *bprm) |
@@ -386,8 +383,8 @@ int cap_bprm_secureexec (struct linux_binprm *bprm) | |||
386 | current->egid != current->gid); | 383 | current->egid != current->gid); |
387 | } | 384 | } |
388 | 385 | ||
389 | int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, | 386 | int cap_inode_setxattr(struct dentry *dentry, const char *name, |
390 | size_t size, int flags) | 387 | const void *value, size_t size, int flags) |
391 | { | 388 | { |
392 | if (!strcmp(name, XATTR_NAME_CAPS)) { | 389 | if (!strcmp(name, XATTR_NAME_CAPS)) { |
393 | if (!capable(CAP_SETFCAP)) | 390 | if (!capable(CAP_SETFCAP)) |
@@ -400,7 +397,7 @@ int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, | |||
400 | return 0; | 397 | return 0; |
401 | } | 398 | } |
402 | 399 | ||
403 | int cap_inode_removexattr(struct dentry *dentry, char *name) | 400 | int cap_inode_removexattr(struct dentry *dentry, const char *name) |
404 | { | 401 | { |
405 | if (!strcmp(name, XATTR_NAME_CAPS)) { | 402 | if (!strcmp(name, XATTR_NAME_CAPS)) { |
406 | if (!capable(CAP_SETFCAP)) | 403 | if (!capable(CAP_SETFCAP)) |
@@ -448,7 +445,7 @@ static inline void cap_emulate_setxuid (int old_ruid, int old_euid, | |||
448 | { | 445 | { |
449 | if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && | 446 | if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && |
450 | (current->uid != 0 && current->euid != 0 && current->suid != 0) && | 447 | (current->uid != 0 && current->euid != 0 && current->suid != 0) && |
451 | !current->keep_capabilities) { | 448 | !issecure(SECURE_KEEP_CAPS)) { |
452 | cap_clear (current->cap_permitted); | 449 | cap_clear (current->cap_permitted); |
453 | cap_clear (current->cap_effective); | 450 | cap_clear (current->cap_effective); |
454 | } | 451 | } |
@@ -547,7 +544,7 @@ int cap_task_setnice (struct task_struct *p, int nice) | |||
547 | * this task could get inconsistent info. There can be no | 544 | * this task could get inconsistent info. There can be no |
548 | * racing writer bc a task can only change its own caps. | 545 | * racing writer bc a task can only change its own caps. |
549 | */ | 546 | */ |
550 | long cap_prctl_drop(unsigned long cap) | 547 | static long cap_prctl_drop(unsigned long cap) |
551 | { | 548 | { |
552 | if (!capable(CAP_SETPCAP)) | 549 | if (!capable(CAP_SETPCAP)) |
553 | return -EPERM; | 550 | return -EPERM; |
@@ -556,6 +553,7 @@ long cap_prctl_drop(unsigned long cap) | |||
556 | cap_lower(current->cap_bset, cap); | 553 | cap_lower(current->cap_bset, cap); |
557 | return 0; | 554 | return 0; |
558 | } | 555 | } |
556 | |||
559 | #else | 557 | #else |
560 | int cap_task_setscheduler (struct task_struct *p, int policy, | 558 | int cap_task_setscheduler (struct task_struct *p, int policy, |
561 | struct sched_param *lp) | 559 | struct sched_param *lp) |
@@ -572,12 +570,99 @@ int cap_task_setnice (struct task_struct *p, int nice) | |||
572 | } | 570 | } |
573 | #endif | 571 | #endif |
574 | 572 | ||
573 | int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | ||
574 | unsigned long arg4, unsigned long arg5, long *rc_p) | ||
575 | { | ||
576 | long error = 0; | ||
577 | |||
578 | switch (option) { | ||
579 | case PR_CAPBSET_READ: | ||
580 | if (!cap_valid(arg2)) | ||
581 | error = -EINVAL; | ||
582 | else | ||
583 | error = !!cap_raised(current->cap_bset, arg2); | ||
584 | break; | ||
585 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES | ||
586 | case PR_CAPBSET_DROP: | ||
587 | error = cap_prctl_drop(arg2); | ||
588 | break; | ||
589 | |||
590 | /* | ||
591 | * The next four prctl's remain to assist with transitioning a | ||
592 | * system from legacy UID=0 based privilege (when filesystem | ||
593 | * capabilities are not in use) to a system using filesystem | ||
594 | * capabilities only - as the POSIX.1e draft intended. | ||
595 | * | ||
596 | * Note: | ||
597 | * | ||
598 | * PR_SET_SECUREBITS = | ||
599 | * issecure_mask(SECURE_KEEP_CAPS_LOCKED) | ||
600 | * | issecure_mask(SECURE_NOROOT) | ||
601 | * | issecure_mask(SECURE_NOROOT_LOCKED) | ||
602 | * | issecure_mask(SECURE_NO_SETUID_FIXUP) | ||
603 | * | issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED) | ||
604 | * | ||
605 | * will ensure that the current process and all of its | ||
606 | * children will be locked into a pure | ||
607 | * capability-based-privilege environment. | ||
608 | */ | ||
609 | case PR_SET_SECUREBITS: | ||
610 | if ((((current->securebits & SECURE_ALL_LOCKS) >> 1) | ||
611 | & (current->securebits ^ arg2)) /*[1]*/ | ||
612 | || ((current->securebits & SECURE_ALL_LOCKS | ||
613 | & ~arg2)) /*[2]*/ | ||
614 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | ||
615 | || (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/ | ||
616 | /* | ||
617 | * [1] no changing of bits that are locked | ||
618 | * [2] no unlocking of locks | ||
619 | * [3] no setting of unsupported bits | ||
620 | * [4] doing anything requires privilege (go read about | ||
621 | * the "sendmail capabilities bug") | ||
622 | */ | ||
623 | error = -EPERM; /* cannot change a locked bit */ | ||
624 | } else { | ||
625 | current->securebits = arg2; | ||
626 | } | ||
627 | break; | ||
628 | case PR_GET_SECUREBITS: | ||
629 | error = current->securebits; | ||
630 | break; | ||
631 | |||
632 | #endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ | ||
633 | |||
634 | case PR_GET_KEEPCAPS: | ||
635 | if (issecure(SECURE_KEEP_CAPS)) | ||
636 | error = 1; | ||
637 | break; | ||
638 | case PR_SET_KEEPCAPS: | ||
639 | if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ | ||
640 | error = -EINVAL; | ||
641 | else if (issecure(SECURE_KEEP_CAPS_LOCKED)) | ||
642 | error = -EPERM; | ||
643 | else if (arg2) | ||
644 | current->securebits |= issecure_mask(SECURE_KEEP_CAPS); | ||
645 | else | ||
646 | current->securebits &= | ||
647 | ~issecure_mask(SECURE_KEEP_CAPS); | ||
648 | break; | ||
649 | |||
650 | default: | ||
651 | /* No functionality available - continue with default */ | ||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | /* Functionality provided */ | ||
656 | *rc_p = error; | ||
657 | return 1; | ||
658 | } | ||
659 | |||
575 | void cap_task_reparent_to_init (struct task_struct *p) | 660 | void cap_task_reparent_to_init (struct task_struct *p) |
576 | { | 661 | { |
577 | cap_set_init_eff(p->cap_effective); | 662 | cap_set_init_eff(p->cap_effective); |
578 | cap_clear(p->cap_inheritable); | 663 | cap_clear(p->cap_inheritable); |
579 | cap_set_full(p->cap_permitted); | 664 | cap_set_full(p->cap_permitted); |
580 | p->keep_capabilities = 0; | 665 | p->securebits = SECUREBITS_DEFAULT; |
581 | return; | 666 | return; |
582 | } | 667 | } |
583 | 668 | ||
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 b0232bbf427b..48cf30226e16 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) && |
@@ -604,7 +605,7 @@ static int dummy_task_kill (struct task_struct *p, struct siginfo *info, | |||
604 | } | 605 | } |
605 | 606 | ||
606 | static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3, | 607 | static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3, |
607 | unsigned long arg4, unsigned long arg5) | 608 | unsigned long arg4, unsigned long arg5, long *rc_p) |
608 | { | 609 | { |
609 | return 0; | 610 | return 0; |
610 | } | 611 | } |
@@ -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/root_plug.c b/security/root_plug.c index 6112d1404c81..a41cf42a4fa0 100644 --- a/security/root_plug.c +++ b/security/root_plug.c | |||
@@ -86,6 +86,7 @@ static struct security_operations rootplug_security_ops = { | |||
86 | 86 | ||
87 | .task_post_setuid = cap_task_post_setuid, | 87 | .task_post_setuid = cap_task_post_setuid, |
88 | .task_reparent_to_init = cap_task_reparent_to_init, | 88 | .task_reparent_to_init = cap_task_reparent_to_init, |
89 | .task_prctl = cap_task_prctl, | ||
89 | 90 | ||
90 | .bprm_check_security = rootplug_bprm_check_security, | 91 | .bprm_check_security = rootplug_bprm_check_security, |
91 | }; | 92 | }; |
diff --git a/security/security.c b/security/security.c index 8a285c7b9962..8e64a29dc55d 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; |
@@ -733,9 +733,9 @@ int security_task_wait(struct task_struct *p) | |||
733 | } | 733 | } |
734 | 734 | ||
735 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 735 | int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
736 | unsigned long arg4, unsigned long arg5) | 736 | unsigned long arg4, unsigned long arg5, long *rc_p) |
737 | { | 737 | { |
738 | return security_ops->task_prctl(option, arg2, arg3, arg4, arg5); | 738 | return security_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p); |
739 | } | 739 | } |
740 | 740 | ||
741 | void security_task_reparent_to_init(struct task_struct *p) | 741 | void security_task_reparent_to_init(struct task_struct *p) |
@@ -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/hooks.c b/security/selinux/hooks.c index 308e2cf17d75..4e4de98941ae 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -2619,7 +2619,7 @@ static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
2619 | return dentry_has_perm(current, mnt, dentry, FILE__GETATTR); | 2619 | return dentry_has_perm(current, mnt, dentry, FILE__GETATTR); |
2620 | } | 2620 | } |
2621 | 2621 | ||
2622 | static int selinux_inode_setotherxattr(struct dentry *dentry, char *name) | 2622 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) |
2623 | { | 2623 | { |
2624 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 2624 | if (!strncmp(name, XATTR_SECURITY_PREFIX, |
2625 | sizeof XATTR_SECURITY_PREFIX - 1)) { | 2625 | sizeof XATTR_SECURITY_PREFIX - 1)) { |
@@ -2638,7 +2638,8 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, char *name) | |||
2638 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); | 2638 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); |
2639 | } | 2639 | } |
2640 | 2640 | ||
2641 | static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags) | 2641 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, |
2642 | const void *value, size_t size, int flags) | ||
2642 | { | 2643 | { |
2643 | struct task_security_struct *tsec = current->security; | 2644 | struct task_security_struct *tsec = current->security; |
2644 | struct inode *inode = dentry->d_inode; | 2645 | struct inode *inode = dentry->d_inode; |
@@ -2687,8 +2688,9 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value | |||
2687 | &ad); | 2688 | &ad); |
2688 | } | 2689 | } |
2689 | 2690 | ||
2690 | static void selinux_inode_post_setxattr(struct dentry *dentry, char *name, | 2691 | static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, |
2691 | void *value, size_t size, int flags) | 2692 | const void *value, size_t size, |
2693 | int flags) | ||
2692 | { | 2694 | { |
2693 | struct inode *inode = dentry->d_inode; | 2695 | struct inode *inode = dentry->d_inode; |
2694 | struct inode_security_struct *isec = inode->i_security; | 2696 | struct inode_security_struct *isec = inode->i_security; |
@@ -2711,7 +2713,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name, | |||
2711 | return; | 2713 | return; |
2712 | } | 2714 | } |
2713 | 2715 | ||
2714 | static int selinux_inode_getxattr(struct dentry *dentry, char *name) | 2716 | static int selinux_inode_getxattr(struct dentry *dentry, const char *name) |
2715 | { | 2717 | { |
2716 | return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); | 2718 | return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); |
2717 | } | 2719 | } |
@@ -2721,7 +2723,7 @@ static int selinux_inode_listxattr(struct dentry *dentry) | |||
2721 | return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); | 2723 | return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); |
2722 | } | 2724 | } |
2723 | 2725 | ||
2724 | static int selinux_inode_removexattr(struct dentry *dentry, char *name) | 2726 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) |
2725 | { | 2727 | { |
2726 | if (strcmp(name, XATTR_NAME_SELINUX)) | 2728 | if (strcmp(name, XATTR_NAME_SELINUX)) |
2727 | return selinux_inode_setotherxattr(dentry, name); | 2729 | return selinux_inode_setotherxattr(dentry, name); |
@@ -3303,12 +3305,13 @@ static int selinux_task_prctl(int option, | |||
3303 | unsigned long arg2, | 3305 | unsigned long arg2, |
3304 | unsigned long arg3, | 3306 | unsigned long arg3, |
3305 | unsigned long arg4, | 3307 | unsigned long arg4, |
3306 | unsigned long arg5) | 3308 | unsigned long arg5, |
3309 | long *rc_p) | ||
3307 | { | 3310 | { |
3308 | /* The current prctl operations do not appear to require | 3311 | /* The current prctl operations do not appear to require |
3309 | any SELinux controls since they merely observe or modify | 3312 | any SELinux controls since they merely observe or modify |
3310 | the state of the current process. */ | 3313 | the state of the current process. */ |
3311 | return 0; | 3314 | return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p); |
3312 | } | 3315 | } |
3313 | 3316 | ||
3314 | static int selinux_task_wait(struct task_struct *p) | 3317 | static int selinux_task_wait(struct task_struct *p) |
@@ -5297,6 +5300,20 @@ static int selinux_key_permission(key_ref_t key_ref, | |||
5297 | SECCLASS_KEY, perm, NULL); | 5300 | SECCLASS_KEY, perm, NULL); |
5298 | } | 5301 | } |
5299 | 5302 | ||
5303 | static int selinux_key_getsecurity(struct key *key, char **_buffer) | ||
5304 | { | ||
5305 | struct key_security_struct *ksec = key->security; | ||
5306 | char *context = NULL; | ||
5307 | unsigned len; | ||
5308 | int rc; | ||
5309 | |||
5310 | rc = security_sid_to_context(ksec->sid, &context, &len); | ||
5311 | if (!rc) | ||
5312 | rc = len; | ||
5313 | *_buffer = context; | ||
5314 | return rc; | ||
5315 | } | ||
5316 | |||
5300 | #endif | 5317 | #endif |
5301 | 5318 | ||
5302 | static struct security_operations selinux_ops = { | 5319 | static struct security_operations selinux_ops = { |
@@ -5485,6 +5502,7 @@ static struct security_operations selinux_ops = { | |||
5485 | .key_alloc = selinux_key_alloc, | 5502 | .key_alloc = selinux_key_alloc, |
5486 | .key_free = selinux_key_free, | 5503 | .key_free = selinux_key_free, |
5487 | .key_permission = selinux_key_permission, | 5504 | .key_permission = selinux_key_permission, |
5505 | .key_getsecurity = selinux_key_getsecurity, | ||
5488 | #endif | 5506 | #endif |
5489 | 5507 | ||
5490 | #ifdef CONFIG_AUDIT | 5508 | #ifdef CONFIG_AUDIT |
@@ -5533,14 +5551,6 @@ static __init int selinux_init(void) | |||
5533 | else | 5551 | else |
5534 | printk(KERN_DEBUG "SELinux: Starting in permissive mode\n"); | 5552 | printk(KERN_DEBUG "SELinux: Starting in permissive mode\n"); |
5535 | 5553 | ||
5536 | #ifdef CONFIG_KEYS | ||
5537 | /* Add security information to initial keyrings */ | ||
5538 | selinux_key_alloc(&root_user_keyring, current, | ||
5539 | KEY_ALLOC_NOT_IN_QUOTA); | ||
5540 | selinux_key_alloc(&root_session_keyring, current, | ||
5541 | KEY_ALLOC_NOT_IN_QUOTA); | ||
5542 | #endif | ||
5543 | |||
5544 | return 0; | 5554 | return 0; |
5545 | } | 5555 | } |
5546 | 5556 | ||
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index ff869e8b6f4a..c0d314d9f8e1 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h | |||
@@ -10,22 +10,19 @@ | |||
10 | 10 | ||
11 | int avc_ss_reset(u32 seqno); | 11 | int avc_ss_reset(u32 seqno); |
12 | 12 | ||
13 | struct av_perm_to_string | 13 | struct av_perm_to_string { |
14 | { | ||
15 | u16 tclass; | 14 | u16 tclass; |
16 | u32 value; | 15 | u32 value; |
17 | const char *name; | 16 | const char *name; |
18 | }; | 17 | }; |
19 | 18 | ||
20 | struct av_inherit | 19 | struct av_inherit { |
21 | { | ||
22 | u16 tclass; | 20 | u16 tclass; |
23 | const char **common_pts; | 21 | const char **common_pts; |
24 | u32 common_base; | 22 | u32 common_base; |
25 | }; | 23 | }; |
26 | 24 | ||
27 | struct selinux_class_perm | 25 | struct selinux_class_perm { |
28 | { | ||
29 | const struct av_perm_to_string *av_perm_to_string; | 26 | const struct av_perm_to_string *av_perm_to_string; |
30 | u32 av_pts_len; | 27 | u32 av_pts_len; |
31 | const char **class_to_string; | 28 | const char **class_to_string; |
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 9a9e7cd9a379..487a7d81fe20 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
@@ -64,7 +64,7 @@ static inline void selinux_netlbl_cache_invalidate(void) | |||
64 | } | 64 | } |
65 | 65 | ||
66 | static inline void selinux_netlbl_sk_security_reset( | 66 | static inline void selinux_netlbl_sk_security_reset( |
67 | struct sk_security_struct *ssec, | 67 | struct sk_security_struct *ssec, |
68 | int family) | 68 | int family) |
69 | { | 69 | { |
70 | return; | 70 | return; |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 300b61bad7b3..032c2357dad1 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -4,16 +4,16 @@ | |||
4 | * This file contains the SELinux security data structures for kernel objects. | 4 | * This file contains the SELinux security data structures for kernel objects. |
5 | * | 5 | * |
6 | * Author(s): Stephen Smalley, <sds@epoch.ncsc.mil> | 6 | * Author(s): Stephen Smalley, <sds@epoch.ncsc.mil> |
7 | * Chris Vance, <cvance@nai.com> | 7 | * Chris Vance, <cvance@nai.com> |
8 | * Wayne Salamon, <wsalamon@nai.com> | 8 | * Wayne Salamon, <wsalamon@nai.com> |
9 | * James Morris <jmorris@redhat.com> | 9 | * James Morris <jmorris@redhat.com> |
10 | * | 10 | * |
11 | * Copyright (C) 2001,2002 Networks Associates Technology, Inc. | 11 | * Copyright (C) 2001,2002 Networks Associates Technology, Inc. |
12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> | 12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License version 2, | 15 | * it under the terms of the GNU General Public License version 2, |
16 | * as published by the Free Software Foundation. | 16 | * as published by the Free Software Foundation. |
17 | */ | 17 | */ |
18 | #ifndef _SELINUX_OBJSEC_H_ | 18 | #ifndef _SELINUX_OBJSEC_H_ |
19 | #define _SELINUX_OBJSEC_H_ | 19 | #define _SELINUX_OBJSEC_H_ |
@@ -28,58 +28,58 @@ | |||
28 | #include "avc.h" | 28 | #include "avc.h" |
29 | 29 | ||
30 | struct task_security_struct { | 30 | struct task_security_struct { |
31 | u32 osid; /* SID prior to last execve */ | 31 | u32 osid; /* SID prior to last execve */ |
32 | u32 sid; /* current SID */ | 32 | u32 sid; /* current SID */ |
33 | u32 exec_sid; /* exec SID */ | 33 | u32 exec_sid; /* exec SID */ |
34 | u32 create_sid; /* fscreate SID */ | 34 | u32 create_sid; /* fscreate SID */ |
35 | u32 keycreate_sid; /* keycreate SID */ | 35 | u32 keycreate_sid; /* keycreate SID */ |
36 | u32 sockcreate_sid; /* fscreate SID */ | 36 | u32 sockcreate_sid; /* fscreate SID */ |
37 | }; | 37 | }; |
38 | 38 | ||
39 | struct inode_security_struct { | 39 | struct inode_security_struct { |
40 | struct inode *inode; /* back pointer to inode object */ | 40 | struct inode *inode; /* back pointer to inode object */ |
41 | struct list_head list; /* list of inode_security_struct */ | 41 | struct list_head list; /* list of inode_security_struct */ |
42 | u32 task_sid; /* SID of creating task */ | 42 | u32 task_sid; /* SID of creating task */ |
43 | u32 sid; /* SID of this object */ | 43 | u32 sid; /* SID of this object */ |
44 | u16 sclass; /* security class of this object */ | 44 | u16 sclass; /* security class of this object */ |
45 | unsigned char initialized; /* initialization flag */ | 45 | unsigned char initialized; /* initialization flag */ |
46 | struct mutex lock; | 46 | struct mutex lock; |
47 | unsigned char inherit; /* inherit SID from parent entry */ | 47 | unsigned char inherit; /* inherit SID from parent entry */ |
48 | }; | 48 | }; |
49 | 49 | ||
50 | struct file_security_struct { | 50 | struct file_security_struct { |
51 | u32 sid; /* SID of open file description */ | 51 | u32 sid; /* SID of open file description */ |
52 | u32 fown_sid; /* SID of file owner (for SIGIO) */ | 52 | u32 fown_sid; /* SID of file owner (for SIGIO) */ |
53 | u32 isid; /* SID of inode at the time of file open */ | 53 | u32 isid; /* SID of inode at the time of file open */ |
54 | u32 pseqno; /* Policy seqno at the time of file open */ | 54 | u32 pseqno; /* Policy seqno at the time of file open */ |
55 | }; | 55 | }; |
56 | 56 | ||
57 | struct superblock_security_struct { | 57 | struct superblock_security_struct { |
58 | struct super_block *sb; /* back pointer to sb object */ | 58 | struct super_block *sb; /* back pointer to sb object */ |
59 | struct list_head list; /* list of superblock_security_struct */ | 59 | struct list_head list; /* list of superblock_security_struct */ |
60 | u32 sid; /* SID of file system superblock */ | 60 | u32 sid; /* SID of file system superblock */ |
61 | u32 def_sid; /* default SID for labeling */ | 61 | u32 def_sid; /* default SID for labeling */ |
62 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ | 62 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ |
63 | unsigned int behavior; /* labeling behavior */ | 63 | unsigned int behavior; /* labeling behavior */ |
64 | unsigned char initialized; /* initialization flag */ | 64 | unsigned char initialized; /* initialization flag */ |
65 | unsigned char flags; /* which mount options were specified */ | 65 | unsigned char flags; /* which mount options were specified */ |
66 | unsigned char proc; /* proc fs */ | 66 | unsigned char proc; /* proc fs */ |
67 | struct mutex lock; | 67 | struct mutex lock; |
68 | struct list_head isec_head; | 68 | struct list_head isec_head; |
69 | spinlock_t isec_lock; | 69 | spinlock_t isec_lock; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | struct msg_security_struct { | 72 | struct msg_security_struct { |
73 | u32 sid; /* SID of message */ | 73 | u32 sid; /* SID of message */ |
74 | }; | 74 | }; |
75 | 75 | ||
76 | struct ipc_security_struct { | 76 | struct ipc_security_struct { |
77 | u16 sclass; /* security class of this object */ | 77 | u16 sclass; /* security class of this object */ |
78 | u32 sid; /* SID of IPC resource */ | 78 | u32 sid; /* SID of IPC resource */ |
79 | }; | 79 | }; |
80 | 80 | ||
81 | struct bprm_security_struct { | 81 | struct bprm_security_struct { |
82 | u32 sid; /* SID for transformed process */ | 82 | u32 sid; /* SID for transformed process */ |
83 | unsigned char set; | 83 | unsigned char set; |
84 | 84 | ||
85 | /* | 85 | /* |
@@ -123,7 +123,7 @@ struct sk_security_struct { | |||
123 | }; | 123 | }; |
124 | 124 | ||
125 | struct key_security_struct { | 125 | struct key_security_struct { |
126 | u32 sid; /* SID of key */ | 126 | u32 sid; /* SID of key */ |
127 | }; | 127 | }; |
128 | 128 | ||
129 | extern unsigned int selinux_checkreqprot; | 129 | extern unsigned int selinux_checkreqprot; |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 1904c462a605..cdb14add27d2 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -62,7 +62,7 @@ enum { | |||
62 | extern int selinux_policycap_netpeer; | 62 | extern int selinux_policycap_netpeer; |
63 | extern int selinux_policycap_openperm; | 63 | extern int selinux_policycap_openperm; |
64 | 64 | ||
65 | int security_load_policy(void * data, size_t len); | 65 | int security_load_policy(void *data, size_t len); |
66 | 66 | ||
67 | int security_policycap_supported(unsigned int req_cap); | 67 | int security_policycap_supported(unsigned int req_cap); |
68 | 68 | ||
@@ -93,7 +93,7 @@ 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(char *scontext, u32 scontext_len, |
@@ -110,7 +110,7 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen, | |||
110 | u32 *out_sid); | 110 | u32 *out_sid); |
111 | 111 | ||
112 | int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, | 112 | int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, |
113 | u16 tclass); | 113 | u16 tclass); |
114 | 114 | ||
115 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); | 115 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); |
116 | 116 | ||
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 2edc4c5e0c61..b6ccd09379f1 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
@@ -40,11 +40,17 @@ | |||
40 | #include <net/ipv6.h> | 40 | #include <net/ipv6.h> |
41 | #include <asm/bug.h> | 41 | #include <asm/bug.h> |
42 | 42 | ||
43 | #include "netnode.h" | ||
43 | #include "objsec.h" | 44 | #include "objsec.h" |
44 | 45 | ||
45 | #define SEL_NETNODE_HASH_SIZE 256 | 46 | #define SEL_NETNODE_HASH_SIZE 256 |
46 | #define SEL_NETNODE_HASH_BKT_LIMIT 16 | 47 | #define SEL_NETNODE_HASH_BKT_LIMIT 16 |
47 | 48 | ||
49 | struct sel_netnode_bkt { | ||
50 | unsigned int size; | ||
51 | struct list_head list; | ||
52 | }; | ||
53 | |||
48 | struct sel_netnode { | 54 | struct sel_netnode { |
49 | struct netnode_security_struct nsec; | 55 | struct netnode_security_struct nsec; |
50 | 56 | ||
@@ -60,7 +66,7 @@ struct sel_netnode { | |||
60 | 66 | ||
61 | static LIST_HEAD(sel_netnode_list); | 67 | static LIST_HEAD(sel_netnode_list); |
62 | static DEFINE_SPINLOCK(sel_netnode_lock); | 68 | static DEFINE_SPINLOCK(sel_netnode_lock); |
63 | static struct list_head sel_netnode_hash[SEL_NETNODE_HASH_SIZE]; | 69 | static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE]; |
64 | 70 | ||
65 | /** | 71 | /** |
66 | * sel_netnode_free - Frees a node entry | 72 | * sel_netnode_free - Frees a node entry |
@@ -87,7 +93,7 @@ static void sel_netnode_free(struct rcu_head *p) | |||
87 | * the bucket number for the given IP address. | 93 | * the bucket number for the given IP address. |
88 | * | 94 | * |
89 | */ | 95 | */ |
90 | static u32 sel_netnode_hashfn_ipv4(__be32 addr) | 96 | static unsigned int sel_netnode_hashfn_ipv4(__be32 addr) |
91 | { | 97 | { |
92 | /* at some point we should determine if the mismatch in byte order | 98 | /* at some point we should determine if the mismatch in byte order |
93 | * affects the hash function dramatically */ | 99 | * affects the hash function dramatically */ |
@@ -103,7 +109,7 @@ static u32 sel_netnode_hashfn_ipv4(__be32 addr) | |||
103 | * the bucket number for the given IP address. | 109 | * the bucket number for the given IP address. |
104 | * | 110 | * |
105 | */ | 111 | */ |
106 | static u32 sel_netnode_hashfn_ipv6(const struct in6_addr *addr) | 112 | static unsigned int sel_netnode_hashfn_ipv6(const struct in6_addr *addr) |
107 | { | 113 | { |
108 | /* just hash the least significant 32 bits to keep things fast (they | 114 | /* just hash the least significant 32 bits to keep things fast (they |
109 | * are the most likely to be different anyway), we can revisit this | 115 | * are the most likely to be different anyway), we can revisit this |
@@ -123,7 +129,7 @@ static u32 sel_netnode_hashfn_ipv6(const struct in6_addr *addr) | |||
123 | */ | 129 | */ |
124 | static struct sel_netnode *sel_netnode_find(const void *addr, u16 family) | 130 | static struct sel_netnode *sel_netnode_find(const void *addr, u16 family) |
125 | { | 131 | { |
126 | u32 idx; | 132 | unsigned int idx; |
127 | struct sel_netnode *node; | 133 | struct sel_netnode *node; |
128 | 134 | ||
129 | switch (family) { | 135 | switch (family) { |
@@ -137,7 +143,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family) | |||
137 | BUG(); | 143 | BUG(); |
138 | } | 144 | } |
139 | 145 | ||
140 | list_for_each_entry_rcu(node, &sel_netnode_hash[idx], list) | 146 | list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list) |
141 | if (node->nsec.family == family) | 147 | if (node->nsec.family == family) |
142 | switch (family) { | 148 | switch (family) { |
143 | case PF_INET: | 149 | case PF_INET: |
@@ -159,15 +165,12 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family) | |||
159 | * @node: the new node record | 165 | * @node: the new node record |
160 | * | 166 | * |
161 | * Description: | 167 | * Description: |
162 | * Add a new node record to the network address hash table. Returns zero on | 168 | * Add a new node record to the network address hash table. |
163 | * success, negative values on failure. | ||
164 | * | 169 | * |
165 | */ | 170 | */ |
166 | static int sel_netnode_insert(struct sel_netnode *node) | 171 | static void sel_netnode_insert(struct sel_netnode *node) |
167 | { | 172 | { |
168 | u32 idx; | 173 | unsigned int idx; |
169 | u32 count = 0; | ||
170 | struct sel_netnode *iter; | ||
171 | 174 | ||
172 | switch (node->nsec.family) { | 175 | switch (node->nsec.family) { |
173 | case PF_INET: | 176 | case PF_INET: |
@@ -179,32 +182,21 @@ static int sel_netnode_insert(struct sel_netnode *node) | |||
179 | default: | 182 | default: |
180 | BUG(); | 183 | BUG(); |
181 | } | 184 | } |
182 | list_add_rcu(&node->list, &sel_netnode_hash[idx]); | 185 | |
186 | INIT_RCU_HEAD(&node->rcu); | ||
183 | 187 | ||
184 | /* we need to impose a limit on the growth of the hash table so check | 188 | /* we need to impose a limit on the growth of the hash table so check |
185 | * this bucket to make sure it is within the specified bounds */ | 189 | * this bucket to make sure it is within the specified bounds */ |
186 | list_for_each_entry(iter, &sel_netnode_hash[idx], list) | 190 | list_add_rcu(&node->list, &sel_netnode_hash[idx].list); |
187 | if (++count > SEL_NETNODE_HASH_BKT_LIMIT) { | 191 | if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) { |
188 | list_del_rcu(&iter->list); | 192 | struct sel_netnode *tail; |
189 | call_rcu(&iter->rcu, sel_netnode_free); | 193 | tail = list_entry( |
190 | break; | 194 | rcu_dereference(sel_netnode_hash[idx].list.prev), |
191 | } | 195 | struct sel_netnode, list); |
192 | 196 | list_del_rcu(&tail->list); | |
193 | return 0; | 197 | call_rcu(&tail->rcu, sel_netnode_free); |
194 | } | 198 | } else |
195 | 199 | sel_netnode_hash[idx].size++; | |
196 | /** | ||
197 | * sel_netnode_destroy - Remove a node record from the table | ||
198 | * @node: the existing node record | ||
199 | * | ||
200 | * Description: | ||
201 | * Remove an existing node record from the network address table. | ||
202 | * | ||
203 | */ | ||
204 | static void sel_netnode_destroy(struct sel_netnode *node) | ||
205 | { | ||
206 | list_del_rcu(&node->list); | ||
207 | call_rcu(&node->rcu, sel_netnode_free); | ||
208 | } | 200 | } |
209 | 201 | ||
210 | /** | 202 | /** |
@@ -222,7 +214,7 @@ static void sel_netnode_destroy(struct sel_netnode *node) | |||
222 | */ | 214 | */ |
223 | static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) | 215 | static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) |
224 | { | 216 | { |
225 | int ret; | 217 | int ret = -ENOMEM; |
226 | struct sel_netnode *node; | 218 | struct sel_netnode *node; |
227 | struct sel_netnode *new = NULL; | 219 | struct sel_netnode *new = NULL; |
228 | 220 | ||
@@ -230,25 +222,21 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) | |||
230 | node = sel_netnode_find(addr, family); | 222 | node = sel_netnode_find(addr, family); |
231 | if (node != NULL) { | 223 | if (node != NULL) { |
232 | *sid = node->nsec.sid; | 224 | *sid = node->nsec.sid; |
233 | ret = 0; | 225 | spin_unlock_bh(&sel_netnode_lock); |
234 | goto out; | 226 | return 0; |
235 | } | 227 | } |
236 | new = kzalloc(sizeof(*new), GFP_ATOMIC); | 228 | new = kzalloc(sizeof(*new), GFP_ATOMIC); |
237 | if (new == NULL) { | 229 | if (new == NULL) |
238 | ret = -ENOMEM; | ||
239 | goto out; | 230 | goto out; |
240 | } | ||
241 | switch (family) { | 231 | switch (family) { |
242 | case PF_INET: | 232 | case PF_INET: |
243 | ret = security_node_sid(PF_INET, | 233 | ret = security_node_sid(PF_INET, |
244 | addr, sizeof(struct in_addr), | 234 | addr, sizeof(struct in_addr), sid); |
245 | &new->nsec.sid); | ||
246 | new->nsec.addr.ipv4 = *(__be32 *)addr; | 235 | new->nsec.addr.ipv4 = *(__be32 *)addr; |
247 | break; | 236 | break; |
248 | case PF_INET6: | 237 | case PF_INET6: |
249 | ret = security_node_sid(PF_INET6, | 238 | ret = security_node_sid(PF_INET6, |
250 | addr, sizeof(struct in6_addr), | 239 | addr, sizeof(struct in6_addr), sid); |
251 | &new->nsec.sid); | ||
252 | ipv6_addr_copy(&new->nsec.addr.ipv6, addr); | 240 | ipv6_addr_copy(&new->nsec.addr.ipv6, addr); |
253 | break; | 241 | break; |
254 | default: | 242 | default: |
@@ -256,11 +244,10 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) | |||
256 | } | 244 | } |
257 | if (ret != 0) | 245 | if (ret != 0) |
258 | goto out; | 246 | goto out; |
247 | |||
259 | new->nsec.family = family; | 248 | new->nsec.family = family; |
260 | ret = sel_netnode_insert(new); | 249 | new->nsec.sid = *sid; |
261 | if (ret != 0) | 250 | sel_netnode_insert(new); |
262 | goto out; | ||
263 | *sid = new->nsec.sid; | ||
264 | 251 | ||
265 | out: | 252 | out: |
266 | spin_unlock_bh(&sel_netnode_lock); | 253 | spin_unlock_bh(&sel_netnode_lock); |
@@ -312,13 +299,18 @@ int sel_netnode_sid(void *addr, u16 family, u32 *sid) | |||
312 | */ | 299 | */ |
313 | static void sel_netnode_flush(void) | 300 | static void sel_netnode_flush(void) |
314 | { | 301 | { |
315 | u32 idx; | 302 | unsigned int idx; |
316 | struct sel_netnode *node; | 303 | struct sel_netnode *node, *node_tmp; |
317 | 304 | ||
318 | spin_lock_bh(&sel_netnode_lock); | 305 | spin_lock_bh(&sel_netnode_lock); |
319 | for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++) | 306 | for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++) { |
320 | list_for_each_entry(node, &sel_netnode_hash[idx], list) | 307 | list_for_each_entry_safe(node, node_tmp, |
321 | sel_netnode_destroy(node); | 308 | &sel_netnode_hash[idx].list, list) { |
309 | list_del_rcu(&node->list); | ||
310 | call_rcu(&node->rcu, sel_netnode_free); | ||
311 | } | ||
312 | sel_netnode_hash[idx].size = 0; | ||
313 | } | ||
322 | spin_unlock_bh(&sel_netnode_lock); | 314 | spin_unlock_bh(&sel_netnode_lock); |
323 | } | 315 | } |
324 | 316 | ||
@@ -340,8 +332,10 @@ static __init int sel_netnode_init(void) | |||
340 | if (!selinux_enabled) | 332 | if (!selinux_enabled) |
341 | return 0; | 333 | return 0; |
342 | 334 | ||
343 | for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++) | 335 | for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++) { |
344 | INIT_LIST_HEAD(&sel_netnode_hash[iter]); | 336 | INIT_LIST_HEAD(&sel_netnode_hash[iter].list); |
337 | sel_netnode_hash[iter].size = 0; | ||
338 | } | ||
345 | 339 | ||
346 | ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET, | 340 | ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET, |
347 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | 341 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); |
diff --git a/security/selinux/netport.c b/security/selinux/netport.c index 68ede3c498ab..90b4cff7c350 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c | |||
@@ -114,8 +114,7 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum) | |||
114 | 114 | ||
115 | idx = sel_netport_hashfn(pnum); | 115 | idx = sel_netport_hashfn(pnum); |
116 | list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list) | 116 | list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list) |
117 | if (port->psec.port == pnum && | 117 | if (port->psec.port == pnum && port->psec.protocol == protocol) |
118 | port->psec.protocol == protocol) | ||
119 | return port; | 118 | return port; |
120 | 119 | ||
121 | return NULL; | 120 | return NULL; |
@@ -126,11 +125,10 @@ static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum) | |||
126 | * @port: the new port record | 125 | * @port: the new port record |
127 | * | 126 | * |
128 | * Description: | 127 | * Description: |
129 | * Add a new port record to the network address hash table. Returns zero on | 128 | * Add a new port record to the network address hash table. |
130 | * success, negative values on failure. | ||
131 | * | 129 | * |
132 | */ | 130 | */ |
133 | static int sel_netport_insert(struct sel_netport *port) | 131 | static void sel_netport_insert(struct sel_netport *port) |
134 | { | 132 | { |
135 | unsigned int idx; | 133 | unsigned int idx; |
136 | 134 | ||
@@ -140,13 +138,13 @@ static int sel_netport_insert(struct sel_netport *port) | |||
140 | list_add_rcu(&port->list, &sel_netport_hash[idx].list); | 138 | list_add_rcu(&port->list, &sel_netport_hash[idx].list); |
141 | if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { | 139 | if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { |
142 | struct sel_netport *tail; | 140 | struct sel_netport *tail; |
143 | tail = list_entry(port->list.prev, struct sel_netport, list); | 141 | tail = list_entry( |
144 | list_del_rcu(port->list.prev); | 142 | rcu_dereference(sel_netport_hash[idx].list.prev), |
143 | struct sel_netport, list); | ||
144 | list_del_rcu(&tail->list); | ||
145 | call_rcu(&tail->rcu, sel_netport_free); | 145 | call_rcu(&tail->rcu, sel_netport_free); |
146 | } else | 146 | } else |
147 | sel_netport_hash[idx].size++; | 147 | sel_netport_hash[idx].size++; |
148 | |||
149 | return 0; | ||
150 | } | 148 | } |
151 | 149 | ||
152 | /** | 150 | /** |
@@ -163,7 +161,7 @@ static int sel_netport_insert(struct sel_netport *port) | |||
163 | */ | 161 | */ |
164 | static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) | 162 | static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) |
165 | { | 163 | { |
166 | int ret; | 164 | int ret = -ENOMEM; |
167 | struct sel_netport *port; | 165 | struct sel_netport *port; |
168 | struct sel_netport *new = NULL; | 166 | struct sel_netport *new = NULL; |
169 | 167 | ||
@@ -171,23 +169,20 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) | |||
171 | port = sel_netport_find(protocol, pnum); | 169 | port = sel_netport_find(protocol, pnum); |
172 | if (port != NULL) { | 170 | if (port != NULL) { |
173 | *sid = port->psec.sid; | 171 | *sid = port->psec.sid; |
174 | ret = 0; | 172 | spin_unlock_bh(&sel_netport_lock); |
175 | goto out; | 173 | return 0; |
176 | } | 174 | } |
177 | new = kzalloc(sizeof(*new), GFP_ATOMIC); | 175 | new = kzalloc(sizeof(*new), GFP_ATOMIC); |
178 | if (new == NULL) { | 176 | if (new == NULL) |
179 | ret = -ENOMEM; | ||
180 | goto out; | 177 | goto out; |
181 | } | 178 | ret = security_port_sid(protocol, pnum, sid); |
182 | ret = security_port_sid(protocol, pnum, &new->psec.sid); | ||
183 | if (ret != 0) | 179 | if (ret != 0) |
184 | goto out; | 180 | goto out; |
181 | |||
185 | new->psec.port = pnum; | 182 | new->psec.port = pnum; |
186 | new->psec.protocol = protocol; | 183 | new->psec.protocol = protocol; |
187 | ret = sel_netport_insert(new); | 184 | new->psec.sid = *sid; |
188 | if (ret != 0) | 185 | sel_netport_insert(new); |
189 | goto out; | ||
190 | *sid = new->psec.sid; | ||
191 | 186 | ||
192 | out: | 187 | out: |
193 | spin_unlock_bh(&sel_netport_lock); | 188 | spin_unlock_bh(&sel_netport_lock); |
@@ -239,11 +234,12 @@ int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid) | |||
239 | static void sel_netport_flush(void) | 234 | static void sel_netport_flush(void) |
240 | { | 235 | { |
241 | unsigned int idx; | 236 | unsigned int idx; |
242 | struct sel_netport *port; | 237 | struct sel_netport *port, *port_tmp; |
243 | 238 | ||
244 | spin_lock_bh(&sel_netport_lock); | 239 | spin_lock_bh(&sel_netport_lock); |
245 | for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) { | 240 | for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) { |
246 | list_for_each_entry(port, &sel_netport_hash[idx].list, list) { | 241 | list_for_each_entry_safe(port, port_tmp, |
242 | &sel_netport_hash[idx].list, list) { | ||
247 | list_del_rcu(&port->list); | 243 | list_del_rcu(&port->list); |
248 | call_rcu(&port->rcu, sel_netport_free); | 244 | call_rcu(&port->rcu, sel_netport_free); |
249 | } | 245 | } |
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index f3a1fc6e5d66..65b9f8366e9c 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h | |||
@@ -59,10 +59,10 @@ struct cond_node { | |||
59 | struct cond_node *next; | 59 | struct cond_node *next; |
60 | }; | 60 | }; |
61 | 61 | ||
62 | int cond_policydb_init(struct policydb* p); | 62 | int cond_policydb_init(struct policydb *p); |
63 | void cond_policydb_destroy(struct policydb* p); | 63 | void cond_policydb_destroy(struct policydb *p); |
64 | 64 | ||
65 | int cond_init_bool_indexes(struct policydb* p); | 65 | int cond_init_bool_indexes(struct policydb *p); |
66 | int cond_destroy_bool(void *key, void *datum, void *p); | 66 | int cond_destroy_bool(void *key, void *datum, void *p); |
67 | 67 | ||
68 | int cond_index_bool(void *key, void *datum, void *datap); | 68 | int cond_index_bool(void *key, void *datum, void *datap); |
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index 2eee0dab524d..b9a6f7fc62fc 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h | |||
@@ -84,9 +84,9 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2) | |||
84 | return 1; | 84 | return 1; |
85 | 85 | ||
86 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && | 86 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && |
87 | ebitmap_cmp(&c1->range.level[0].cat,&c2->range.level[0].cat) && | 87 | ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && |
88 | (c1->range.level[1].sens == c2->range.level[1].sens) && | 88 | (c1->range.level[1].sens == c2->range.level[1].sens) && |
89 | ebitmap_cmp(&c1->range.level[1].cat,&c2->range.level[1].cat)); | 89 | ebitmap_cmp(&c1->range.level[1].cat, &c2->range.level[1].cat)); |
90 | } | 90 | } |
91 | 91 | ||
92 | static inline void mls_context_destroy(struct context *c) | 92 | static inline void mls_context_destroy(struct context *c) |
diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h index 7e2ff3e3c6d2..953872cd84ab 100644 --- a/security/selinux/ss/hashtab.h +++ b/security/selinux/ss/hashtab.h | |||
@@ -40,8 +40,8 @@ struct hashtab_info { | |||
40 | * the new hash table otherwise. | 40 | * the new hash table otherwise. |
41 | */ | 41 | */ |
42 | struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), | 42 | struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), |
43 | int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), | 43 | int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), |
44 | u32 size); | 44 | u32 size); |
45 | 45 | ||
46 | /* | 46 | /* |
47 | * Inserts the specified (key, datum) pair into the specified hash table. | 47 | * Inserts the specified (key, datum) pair into the specified hash table. |
@@ -49,7 +49,7 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void * | |||
49 | * Returns -ENOMEM on memory allocation error, | 49 | * Returns -ENOMEM on memory allocation error, |
50 | * -EEXIST if there is already an entry with the same key, | 50 | * -EEXIST if there is already an entry with the same key, |
51 | * -EINVAL for general errors or | 51 | * -EINVAL for general errors or |
52 | * 0 otherwise. | 52 | 0 otherwise. |
53 | */ | 53 | */ |
54 | int hashtab_insert(struct hashtab *h, void *k, void *d); | 54 | int hashtab_insert(struct hashtab *h, void *k, void *d); |
55 | 55 | ||
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index ab53663d9f5f..0fdf6257ef64 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h | |||
@@ -13,7 +13,7 @@ | |||
13 | /* | 13 | /* |
14 | * Updated: Hewlett-Packard <paul.moore@hp.com> | 14 | * Updated: Hewlett-Packard <paul.moore@hp.com> |
15 | * | 15 | * |
16 | * Added support to import/export the MLS label from NetLabel | 16 | * Added support to import/export the MLS label from NetLabel |
17 | * | 17 | * |
18 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 18 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 |
19 | */ | 19 | */ |
@@ -31,7 +31,7 @@ int mls_range_isvalid(struct policydb *p, struct mls_range *r); | |||
31 | int mls_level_isvalid(struct policydb *p, struct mls_level *l); | 31 | int mls_level_isvalid(struct policydb *p, struct mls_level *l); |
32 | 32 | ||
33 | int mls_context_to_sid(char oldc, | 33 | int mls_context_to_sid(char oldc, |
34 | char **scontext, | 34 | char **scontext, |
35 | struct context *context, | 35 | struct context *context, |
36 | struct sidtab *s, | 36 | struct sidtab *s, |
37 | u32 def_sid); | 37 | u32 def_sid); |
@@ -49,7 +49,7 @@ int mls_compute_sid(struct context *scontext, | |||
49 | struct context *newcontext); | 49 | struct context *newcontext); |
50 | 50 | ||
51 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, | 51 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, |
52 | struct context *usercon); | 52 | struct context *usercon); |
53 | 53 | ||
54 | #ifdef CONFIG_NETLABEL | 54 | #ifdef CONFIG_NETLABEL |
55 | void mls_export_netlbl_lvl(struct context *context, | 55 | void mls_export_netlbl_lvl(struct context *context, |
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index 0c692d58d489..b6e943a21061 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h | |||
@@ -31,7 +31,7 @@ static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) | |||
31 | return 1; | 31 | return 1; |
32 | 32 | ||
33 | return ((l1->sens == l2->sens) && | 33 | return ((l1->sens == l2->sens) && |
34 | ebitmap_cmp(&l1->cat, &l2->cat)); | 34 | ebitmap_cmp(&l1->cat, &l2->cat)); |
35 | } | 35 | } |
36 | 36 | ||
37 | static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) | 37 | static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) |
@@ -40,7 +40,7 @@ static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) | |||
40 | return 1; | 40 | return 1; |
41 | 41 | ||
42 | return ((l1->sens >= l2->sens) && | 42 | return ((l1->sens >= l2->sens) && |
43 | ebitmap_contains(&l1->cat, &l2->cat)); | 43 | ebitmap_contains(&l1->cat, &l2->cat)); |
44 | } | 44 | } |
45 | 45 | ||
46 | #define mls_level_incomp(l1, l2) \ | 46 | #define mls_level_incomp(l1, l2) \ |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index ba593a3da877..4253370fda6a 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -12,12 +12,12 @@ | |||
12 | * | 12 | * |
13 | * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> | 13 | * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> |
14 | * | 14 | * |
15 | * Added conditional policy language extensions | 15 | * Added conditional policy language extensions |
16 | * | 16 | * |
17 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. | 17 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. |
18 | * Copyright (C) 2003 - 2004 Tresys Technology, LLC | 18 | * Copyright (C) 2003 - 2004 Tresys Technology, LLC |
19 | * This program is free software; you can redistribute it and/or modify | 19 | * This program is free software; you can redistribute it and/or modify |
20 | * it under the terms of the GNU General Public License as published by | 20 | * it under the terms of the GNU General Public License as published by |
21 | * the Free Software Foundation, version 2. | 21 | * the Free Software Foundation, version 2. |
22 | */ | 22 | */ |
23 | 23 | ||
@@ -221,7 +221,7 @@ struct policydb { | |||
221 | /* type enforcement conditional access vectors and transitions */ | 221 | /* type enforcement conditional access vectors and transitions */ |
222 | struct avtab te_cond_avtab; | 222 | struct avtab te_cond_avtab; |
223 | /* linked list indexing te_cond_avtab by conditional */ | 223 | /* linked list indexing te_cond_avtab by conditional */ |
224 | struct cond_node* cond_list; | 224 | struct cond_node *cond_list; |
225 | 225 | ||
226 | /* role allows */ | 226 | /* role allows */ |
227 | struct role_allow *role_allow; | 227 | struct role_allow *role_allow; |
@@ -230,10 +230,10 @@ struct policydb { | |||
230 | TCP or UDP port numbers, network interfaces and nodes */ | 230 | TCP or UDP port numbers, network interfaces and nodes */ |
231 | struct ocontext *ocontexts[OCON_NUM]; | 231 | struct ocontext *ocontexts[OCON_NUM]; |
232 | 232 | ||
233 | /* security contexts for files in filesystems that cannot support | 233 | /* security contexts for files in filesystems that cannot support |
234 | a persistent label mapping or use another | 234 | a persistent label mapping or use another |
235 | fixed labeling behavior. */ | 235 | fixed labeling behavior. */ |
236 | struct genfs *genfs; | 236 | struct genfs *genfs; |
237 | 237 | ||
238 | /* range transitions */ | 238 | /* range transitions */ |
239 | struct range_trans *range_tr; | 239 | struct range_trans *range_tr; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 2daaddbb301d..25cac5a2aa8e 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); |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 4215971434e6..5d2ec5650e61 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -574,8 +574,8 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
574 | * | 574 | * |
575 | * Returns 0 if access is permitted, an error code otherwise | 575 | * Returns 0 if access is permitted, an error code otherwise |
576 | */ | 576 | */ |
577 | static int smack_inode_setxattr(struct dentry *dentry, char *name, | 577 | static int smack_inode_setxattr(struct dentry *dentry, const char *name, |
578 | void *value, size_t size, int flags) | 578 | const void *value, size_t size, int flags) |
579 | { | 579 | { |
580 | int rc = 0; | 580 | int rc = 0; |
581 | 581 | ||
@@ -604,8 +604,8 @@ static int smack_inode_setxattr(struct dentry *dentry, char *name, | |||
604 | * Set the pointer in the inode blob to the entry found | 604 | * Set the pointer in the inode blob to the entry found |
605 | * in the master label list. | 605 | * in the master label list. |
606 | */ | 606 | */ |
607 | static void smack_inode_post_setxattr(struct dentry *dentry, char *name, | 607 | static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, |
608 | void *value, size_t size, int flags) | 608 | const void *value, size_t size, int flags) |
609 | { | 609 | { |
610 | struct inode_smack *isp; | 610 | struct inode_smack *isp; |
611 | char *nsp; | 611 | char *nsp; |
@@ -641,7 +641,7 @@ static void smack_inode_post_setxattr(struct dentry *dentry, char *name, | |||
641 | * | 641 | * |
642 | * Returns 0 if access is permitted, an error code otherwise | 642 | * Returns 0 if access is permitted, an error code otherwise |
643 | */ | 643 | */ |
644 | static int smack_inode_getxattr(struct dentry *dentry, char *name) | 644 | static int smack_inode_getxattr(struct dentry *dentry, const char *name) |
645 | { | 645 | { |
646 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ); | 646 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ); |
647 | } | 647 | } |
@@ -655,7 +655,7 @@ static int smack_inode_getxattr(struct dentry *dentry, char *name) | |||
655 | * | 655 | * |
656 | * Returns 0 if access is permitted, an error code otherwise | 656 | * Returns 0 if access is permitted, an error code otherwise |
657 | */ | 657 | */ |
658 | static int smack_inode_removexattr(struct dentry *dentry, char *name) | 658 | static int smack_inode_removexattr(struct dentry *dentry, const char *name) |
659 | { | 659 | { |
660 | int rc = 0; | 660 | int rc = 0; |
661 | 661 | ||
@@ -1242,7 +1242,7 @@ static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap) | |||
1242 | int rc; | 1242 | int rc; |
1243 | int byte; | 1243 | int byte; |
1244 | 1244 | ||
1245 | if (catset == 0) | 1245 | if (!catset) |
1246 | return; | 1246 | return; |
1247 | 1247 | ||
1248 | sap->flags |= NETLBL_SECATTR_MLS_CAT; | 1248 | sap->flags |= NETLBL_SECATTR_MLS_CAT; |
@@ -2495,6 +2495,7 @@ struct security_operations smack_ops = { | |||
2495 | .task_wait = smack_task_wait, | 2495 | .task_wait = smack_task_wait, |
2496 | .task_reparent_to_init = cap_task_reparent_to_init, | 2496 | .task_reparent_to_init = cap_task_reparent_to_init, |
2497 | .task_to_inode = smack_task_to_inode, | 2497 | .task_to_inode = smack_task_to_inode, |
2498 | .task_prctl = cap_task_prctl, | ||
2498 | 2499 | ||
2499 | .ipc_permission = smack_ipc_permission, | 2500 | .ipc_permission = smack_ipc_permission, |
2500 | 2501 | ||
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 5d1bee0fa513..271a835fbbe3 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -317,7 +317,7 @@ static const struct file_operations smk_load_ops = { | |||
317 | /** | 317 | /** |
318 | * smk_cipso_doi - initialize the CIPSO domain | 318 | * smk_cipso_doi - initialize the CIPSO domain |
319 | */ | 319 | */ |
320 | void smk_cipso_doi(void) | 320 | static void smk_cipso_doi(void) |
321 | { | 321 | { |
322 | int rc; | 322 | int rc; |
323 | struct cipso_v4_doi *doip; | 323 | struct cipso_v4_doi *doip; |
@@ -351,7 +351,7 @@ void smk_cipso_doi(void) | |||
351 | /** | 351 | /** |
352 | * smk_unlbl_ambient - initialize the unlabeled domain | 352 | * smk_unlbl_ambient - initialize the unlabeled domain |
353 | */ | 353 | */ |
354 | void smk_unlbl_ambient(char *oldambient) | 354 | static void smk_unlbl_ambient(char *oldambient) |
355 | { | 355 | { |
356 | int rc; | 356 | int rc; |
357 | struct netlbl_audit audit_info; | 357 | struct netlbl_audit audit_info; |