diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/Kconfig | 10 | ||||
-rw-r--r-- | security/capability.c | 6 | ||||
-rw-r--r-- | security/commoncap.c | 244 | ||||
-rw-r--r-- | security/dummy.c | 12 | ||||
-rw-r--r-- | security/security.c | 10 | ||||
-rw-r--r-- | security/selinux/hooks.c | 74 |
6 files changed, 313 insertions, 43 deletions
diff --git a/security/Kconfig b/security/Kconfig index a94ee94cf491..8086e61058e3 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -80,6 +80,16 @@ config SECURITY_CAPABILITIES | |||
80 | This enables the "default" Linux capabilities functionality. | 80 | This enables the "default" Linux capabilities functionality. |
81 | If you are unsure how to answer this question, answer Y. | 81 | If you are unsure how to answer this question, answer Y. |
82 | 82 | ||
83 | config SECURITY_FILE_CAPABILITIES | ||
84 | bool "File POSIX Capabilities (EXPERIMENTAL)" | ||
85 | depends on (SECURITY=n || SECURITY_CAPABILITIES!=n) && EXPERIMENTAL | ||
86 | default n | ||
87 | help | ||
88 | This enables filesystem capabilities, allowing you to give | ||
89 | binaries a subset of root's powers without using setuid 0. | ||
90 | |||
91 | If in doubt, answer N. | ||
92 | |||
83 | config SECURITY_ROOTPLUG | 93 | config SECURITY_ROOTPLUG |
84 | bool "Root Plug Support" | 94 | bool "Root Plug Support" |
85 | depends on USB=y && SECURITY | 95 | depends on USB=y && SECURITY |
diff --git a/security/capability.c b/security/capability.c index fda6a14cb24d..9e99f36a8b5c 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -37,7 +37,13 @@ static struct security_operations capability_ops = { | |||
37 | 37 | ||
38 | .inode_setxattr = cap_inode_setxattr, | 38 | .inode_setxattr = cap_inode_setxattr, |
39 | .inode_removexattr = cap_inode_removexattr, | 39 | .inode_removexattr = cap_inode_removexattr, |
40 | .inode_need_killpriv = cap_inode_need_killpriv, | ||
41 | .inode_killpriv = cap_inode_killpriv, | ||
40 | 42 | ||
43 | .task_kill = cap_task_kill, | ||
44 | .task_setscheduler = cap_task_setscheduler, | ||
45 | .task_setioprio = cap_task_setioprio, | ||
46 | .task_setnice = cap_task_setnice, | ||
41 | .task_post_setuid = cap_task_post_setuid, | 47 | .task_post_setuid = cap_task_post_setuid, |
42 | .task_reparent_to_init = cap_task_reparent_to_init, | 48 | .task_reparent_to_init = cap_task_reparent_to_init, |
43 | 49 | ||
diff --git a/security/commoncap.c b/security/commoncap.c index 0f8a2ce3f3a6..afca6dd4ae69 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/xattr.h> | 23 | #include <linux/xattr.h> |
24 | #include <linux/hugetlb.h> | 24 | #include <linux/hugetlb.h> |
25 | #include <linux/mount.h> | ||
25 | 26 | ||
26 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) | 27 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) |
27 | { | 28 | { |
@@ -108,14 +109,130 @@ void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, | |||
108 | target->cap_permitted = *permitted; | 109 | target->cap_permitted = *permitted; |
109 | } | 110 | } |
110 | 111 | ||
112 | static inline void bprm_clear_caps(struct linux_binprm *bprm) | ||
113 | { | ||
114 | cap_clear(bprm->cap_inheritable); | ||
115 | cap_clear(bprm->cap_permitted); | ||
116 | bprm->cap_effective = false; | ||
117 | } | ||
118 | |||
119 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES | ||
120 | |||
121 | int cap_inode_need_killpriv(struct dentry *dentry) | ||
122 | { | ||
123 | struct inode *inode = dentry->d_inode; | ||
124 | int error; | ||
125 | |||
126 | if (!inode->i_op || !inode->i_op->getxattr) | ||
127 | return 0; | ||
128 | |||
129 | error = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, NULL, 0); | ||
130 | if (error <= 0) | ||
131 | return 0; | ||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | int cap_inode_killpriv(struct dentry *dentry) | ||
136 | { | ||
137 | struct inode *inode = dentry->d_inode; | ||
138 | |||
139 | if (!inode->i_op || !inode->i_op->removexattr) | ||
140 | return 0; | ||
141 | |||
142 | return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS); | ||
143 | } | ||
144 | |||
145 | static inline int cap_from_disk(__le32 *caps, struct linux_binprm *bprm, | ||
146 | int size) | ||
147 | { | ||
148 | __u32 magic_etc; | ||
149 | |||
150 | if (size != XATTR_CAPS_SZ) | ||
151 | return -EINVAL; | ||
152 | |||
153 | magic_etc = le32_to_cpu(caps[0]); | ||
154 | |||
155 | switch ((magic_etc & VFS_CAP_REVISION_MASK)) { | ||
156 | case VFS_CAP_REVISION: | ||
157 | if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) | ||
158 | bprm->cap_effective = true; | ||
159 | else | ||
160 | bprm->cap_effective = false; | ||
161 | bprm->cap_permitted = to_cap_t( le32_to_cpu(caps[1]) ); | ||
162 | bprm->cap_inheritable = to_cap_t( le32_to_cpu(caps[2]) ); | ||
163 | return 0; | ||
164 | default: | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | /* Locate any VFS capabilities: */ | ||
170 | static int get_file_caps(struct linux_binprm *bprm) | ||
171 | { | ||
172 | struct dentry *dentry; | ||
173 | int rc = 0; | ||
174 | __le32 v1caps[XATTR_CAPS_SZ]; | ||
175 | struct inode *inode; | ||
176 | |||
177 | if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) { | ||
178 | bprm_clear_caps(bprm); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | dentry = dget(bprm->file->f_dentry); | ||
183 | inode = dentry->d_inode; | ||
184 | if (!inode->i_op || !inode->i_op->getxattr) | ||
185 | goto out; | ||
186 | |||
187 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &v1caps, | ||
188 | XATTR_CAPS_SZ); | ||
189 | if (rc == -ENODATA || rc == -EOPNOTSUPP) { | ||
190 | /* no data, that's ok */ | ||
191 | rc = 0; | ||
192 | goto out; | ||
193 | } | ||
194 | if (rc < 0) | ||
195 | goto out; | ||
196 | |||
197 | rc = cap_from_disk(v1caps, bprm, rc); | ||
198 | if (rc) | ||
199 | printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", | ||
200 | __FUNCTION__, rc, bprm->filename); | ||
201 | |||
202 | out: | ||
203 | dput(dentry); | ||
204 | if (rc) | ||
205 | bprm_clear_caps(bprm); | ||
206 | |||
207 | return rc; | ||
208 | } | ||
209 | |||
210 | #else | ||
211 | int cap_inode_need_killpriv(struct dentry *dentry) | ||
212 | { | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | int cap_inode_killpriv(struct dentry *dentry) | ||
217 | { | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static inline int get_file_caps(struct linux_binprm *bprm) | ||
222 | { | ||
223 | bprm_clear_caps(bprm); | ||
224 | return 0; | ||
225 | } | ||
226 | #endif | ||
227 | |||
111 | int cap_bprm_set_security (struct linux_binprm *bprm) | 228 | int cap_bprm_set_security (struct linux_binprm *bprm) |
112 | { | 229 | { |
113 | /* Copied from fs/exec.c:prepare_binprm. */ | 230 | int ret; |
114 | 231 | ||
115 | /* We don't have VFS support for capabilities yet */ | 232 | ret = get_file_caps(bprm); |
116 | cap_clear (bprm->cap_inheritable); | 233 | if (ret) |
117 | cap_clear (bprm->cap_permitted); | 234 | printk(KERN_NOTICE "%s: get_file_caps returned %d for %s\n", |
118 | cap_clear (bprm->cap_effective); | 235 | __FUNCTION__, ret, bprm->filename); |
119 | 236 | ||
120 | /* To support inheritance of root-permissions and suid-root | 237 | /* To support inheritance of root-permissions and suid-root |
121 | * executables under compatibility mode, we raise all three | 238 | * executables under compatibility mode, we raise all three |
@@ -131,9 +248,10 @@ int cap_bprm_set_security (struct linux_binprm *bprm) | |||
131 | cap_set_full (bprm->cap_permitted); | 248 | cap_set_full (bprm->cap_permitted); |
132 | } | 249 | } |
133 | if (bprm->e_uid == 0) | 250 | if (bprm->e_uid == 0) |
134 | cap_set_full (bprm->cap_effective); | 251 | bprm->cap_effective = true; |
135 | } | 252 | } |
136 | return 0; | 253 | |
254 | return ret; | ||
137 | } | 255 | } |
138 | 256 | ||
139 | void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | 257 | void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) |
@@ -149,6 +267,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
149 | if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || | 267 | if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || |
150 | !cap_issubset (new_permitted, current->cap_permitted)) { | 268 | !cap_issubset (new_permitted, current->cap_permitted)) { |
151 | set_dumpable(current->mm, suid_dumpable); | 269 | set_dumpable(current->mm, suid_dumpable); |
270 | current->pdeath_signal = 0; | ||
152 | 271 | ||
153 | if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) { | 272 | if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) { |
154 | if (!capable(CAP_SETUID)) { | 273 | if (!capable(CAP_SETUID)) { |
@@ -170,8 +289,8 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
170 | * capability rules */ | 289 | * capability rules */ |
171 | if (!is_init(current)) { | 290 | if (!is_init(current)) { |
172 | current->cap_permitted = new_permitted; | 291 | current->cap_permitted = new_permitted; |
173 | current->cap_effective = | 292 | current->cap_effective = bprm->cap_effective ? |
174 | cap_intersect (new_permitted, bprm->cap_effective); | 293 | new_permitted : 0; |
175 | } | 294 | } |
176 | 295 | ||
177 | /* AUD: Audit candidate if current->cap_effective is set */ | 296 | /* AUD: Audit candidate if current->cap_effective is set */ |
@@ -181,11 +300,15 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | |||
181 | 300 | ||
182 | int cap_bprm_secureexec (struct linux_binprm *bprm) | 301 | int cap_bprm_secureexec (struct linux_binprm *bprm) |
183 | { | 302 | { |
184 | /* If/when this module is enhanced to incorporate capability | 303 | if (current->uid != 0) { |
185 | bits on files, the test below should be extended to also perform a | 304 | if (bprm->cap_effective) |
186 | test between the old and new capability sets. For now, | 305 | return 1; |
187 | it simply preserves the legacy decision algorithm used by | 306 | if (!cap_isclear(bprm->cap_permitted)) |
188 | the old userland. */ | 307 | return 1; |
308 | if (!cap_isclear(bprm->cap_inheritable)) | ||
309 | return 1; | ||
310 | } | ||
311 | |||
189 | return (current->euid != current->uid || | 312 | return (current->euid != current->uid || |
190 | current->egid != current->gid); | 313 | current->egid != current->gid); |
191 | } | 314 | } |
@@ -193,7 +316,11 @@ int cap_bprm_secureexec (struct linux_binprm *bprm) | |||
193 | int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, | 316 | int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, |
194 | size_t size, int flags) | 317 | size_t size, int flags) |
195 | { | 318 | { |
196 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 319 | if (!strcmp(name, XATTR_NAME_CAPS)) { |
320 | if (!capable(CAP_SETFCAP)) | ||
321 | return -EPERM; | ||
322 | return 0; | ||
323 | } else if (!strncmp(name, XATTR_SECURITY_PREFIX, | ||
197 | sizeof(XATTR_SECURITY_PREFIX) - 1) && | 324 | sizeof(XATTR_SECURITY_PREFIX) - 1) && |
198 | !capable(CAP_SYS_ADMIN)) | 325 | !capable(CAP_SYS_ADMIN)) |
199 | return -EPERM; | 326 | return -EPERM; |
@@ -202,7 +329,11 @@ int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, | |||
202 | 329 | ||
203 | int cap_inode_removexattr(struct dentry *dentry, char *name) | 330 | int cap_inode_removexattr(struct dentry *dentry, char *name) |
204 | { | 331 | { |
205 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 332 | if (!strcmp(name, XATTR_NAME_CAPS)) { |
333 | if (!capable(CAP_SETFCAP)) | ||
334 | return -EPERM; | ||
335 | return 0; | ||
336 | } else if (!strncmp(name, XATTR_SECURITY_PREFIX, | ||
206 | sizeof(XATTR_SECURITY_PREFIX) - 1) && | 337 | sizeof(XATTR_SECURITY_PREFIX) - 1) && |
207 | !capable(CAP_SYS_ADMIN)) | 338 | !capable(CAP_SYS_ADMIN)) |
208 | return -EPERM; | 339 | return -EPERM; |
@@ -299,6 +430,83 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, | |||
299 | return 0; | 430 | return 0; |
300 | } | 431 | } |
301 | 432 | ||
433 | #ifdef CONFIG_SECURITY_FILE_CAPABILITIES | ||
434 | /* | ||
435 | * Rationale: code calling task_setscheduler, task_setioprio, and | ||
436 | * task_setnice, assumes that | ||
437 | * . if capable(cap_sys_nice), then those actions should be allowed | ||
438 | * . if not capable(cap_sys_nice), but acting on your own processes, | ||
439 | * then those actions should be allowed | ||
440 | * This is insufficient now since you can call code without suid, but | ||
441 | * yet with increased caps. | ||
442 | * So we check for increased caps on the target process. | ||
443 | */ | ||
444 | static inline int cap_safe_nice(struct task_struct *p) | ||
445 | { | ||
446 | if (!cap_issubset(p->cap_permitted, current->cap_permitted) && | ||
447 | !__capable(current, CAP_SYS_NICE)) | ||
448 | return -EPERM; | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | int cap_task_setscheduler (struct task_struct *p, int policy, | ||
453 | struct sched_param *lp) | ||
454 | { | ||
455 | return cap_safe_nice(p); | ||
456 | } | ||
457 | |||
458 | int cap_task_setioprio (struct task_struct *p, int ioprio) | ||
459 | { | ||
460 | return cap_safe_nice(p); | ||
461 | } | ||
462 | |||
463 | int cap_task_setnice (struct task_struct *p, int nice) | ||
464 | { | ||
465 | return cap_safe_nice(p); | ||
466 | } | ||
467 | |||
468 | int cap_task_kill(struct task_struct *p, struct siginfo *info, | ||
469 | int sig, u32 secid) | ||
470 | { | ||
471 | if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info))) | ||
472 | return 0; | ||
473 | |||
474 | if (secid) | ||
475 | /* | ||
476 | * Signal sent as a particular user. | ||
477 | * Capabilities are ignored. May be wrong, but it's the | ||
478 | * only thing we can do at the moment. | ||
479 | * Used only by usb drivers? | ||
480 | */ | ||
481 | return 0; | ||
482 | if (cap_issubset(p->cap_permitted, current->cap_permitted)) | ||
483 | return 0; | ||
484 | if (capable(CAP_KILL)) | ||
485 | return 0; | ||
486 | |||
487 | return -EPERM; | ||
488 | } | ||
489 | #else | ||
490 | int cap_task_setscheduler (struct task_struct *p, int policy, | ||
491 | struct sched_param *lp) | ||
492 | { | ||
493 | return 0; | ||
494 | } | ||
495 | int cap_task_setioprio (struct task_struct *p, int ioprio) | ||
496 | { | ||
497 | return 0; | ||
498 | } | ||
499 | int cap_task_setnice (struct task_struct *p, int nice) | ||
500 | { | ||
501 | return 0; | ||
502 | } | ||
503 | int cap_task_kill(struct task_struct *p, struct siginfo *info, | ||
504 | int sig, u32 secid) | ||
505 | { | ||
506 | return 0; | ||
507 | } | ||
508 | #endif | ||
509 | |||
302 | void cap_task_reparent_to_init (struct task_struct *p) | 510 | void cap_task_reparent_to_init (struct task_struct *p) |
303 | { | 511 | { |
304 | p->cap_effective = CAP_INIT_EFF_SET; | 512 | p->cap_effective = CAP_INIT_EFF_SET; |
@@ -336,6 +544,10 @@ EXPORT_SYMBOL(cap_bprm_secureexec); | |||
336 | EXPORT_SYMBOL(cap_inode_setxattr); | 544 | EXPORT_SYMBOL(cap_inode_setxattr); |
337 | EXPORT_SYMBOL(cap_inode_removexattr); | 545 | EXPORT_SYMBOL(cap_inode_removexattr); |
338 | EXPORT_SYMBOL(cap_task_post_setuid); | 546 | EXPORT_SYMBOL(cap_task_post_setuid); |
547 | EXPORT_SYMBOL(cap_task_kill); | ||
548 | EXPORT_SYMBOL(cap_task_setscheduler); | ||
549 | EXPORT_SYMBOL(cap_task_setioprio); | ||
550 | EXPORT_SYMBOL(cap_task_setnice); | ||
339 | EXPORT_SYMBOL(cap_task_reparent_to_init); | 551 | EXPORT_SYMBOL(cap_task_reparent_to_init); |
340 | EXPORT_SYMBOL(cap_syslog); | 552 | EXPORT_SYMBOL(cap_syslog); |
341 | EXPORT_SYMBOL(cap_vm_enough_memory); | 553 | EXPORT_SYMBOL(cap_vm_enough_memory); |
diff --git a/security/dummy.c b/security/dummy.c index 4129dcf3daec..c77dec822385 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -376,6 +376,16 @@ static int dummy_inode_removexattr (struct dentry *dentry, char *name) | |||
376 | return 0; | 376 | return 0; |
377 | } | 377 | } |
378 | 378 | ||
379 | static int dummy_inode_need_killpriv(struct dentry *dentry) | ||
380 | { | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static int dummy_inode_killpriv(struct dentry *dentry) | ||
385 | { | ||
386 | return 0; | ||
387 | } | ||
388 | |||
379 | static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err) | 389 | static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err) |
380 | { | 390 | { |
381 | return -EOPNOTSUPP; | 391 | return -EOPNOTSUPP; |
@@ -1022,6 +1032,8 @@ void security_fixup_ops (struct security_operations *ops) | |||
1022 | set_to_dummy_if_null(ops, inode_getxattr); | 1032 | set_to_dummy_if_null(ops, inode_getxattr); |
1023 | set_to_dummy_if_null(ops, inode_listxattr); | 1033 | set_to_dummy_if_null(ops, inode_listxattr); |
1024 | set_to_dummy_if_null(ops, inode_removexattr); | 1034 | set_to_dummy_if_null(ops, inode_removexattr); |
1035 | set_to_dummy_if_null(ops, inode_need_killpriv); | ||
1036 | set_to_dummy_if_null(ops, inode_killpriv); | ||
1025 | set_to_dummy_if_null(ops, inode_xattr_getsuffix); | 1037 | set_to_dummy_if_null(ops, inode_xattr_getsuffix); |
1026 | set_to_dummy_if_null(ops, inode_getsecurity); | 1038 | set_to_dummy_if_null(ops, inode_getsecurity); |
1027 | set_to_dummy_if_null(ops, inode_setsecurity); | 1039 | set_to_dummy_if_null(ops, inode_setsecurity); |
diff --git a/security/security.c b/security/security.c index 5b1c034815a8..2e1b35dd2550 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -518,6 +518,16 @@ int security_inode_removexattr(struct dentry *dentry, char *name) | |||
518 | return security_ops->inode_removexattr(dentry, name); | 518 | return security_ops->inode_removexattr(dentry, name); |
519 | } | 519 | } |
520 | 520 | ||
521 | int security_inode_need_killpriv(struct dentry *dentry) | ||
522 | { | ||
523 | return security_ops->inode_need_killpriv(dentry); | ||
524 | } | ||
525 | |||
526 | int security_inode_killpriv(struct dentry *dentry) | ||
527 | { | ||
528 | return security_ops->inode_killpriv(dentry); | ||
529 | } | ||
530 | |||
521 | const char *security_inode_xattr_getsuffix(void) | 531 | const char *security_inode_xattr_getsuffix(void) |
522 | { | 532 | { |
523 | return security_ops->inode_xattr_getsuffix(); | 533 | return security_ops->inode_xattr_getsuffix(); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 83a535b7bc60..221def6a0b1d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -2297,6 +2297,25 @@ static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
2297 | return dentry_has_perm(current, mnt, dentry, FILE__GETATTR); | 2297 | return dentry_has_perm(current, mnt, dentry, FILE__GETATTR); |
2298 | } | 2298 | } |
2299 | 2299 | ||
2300 | static int selinux_inode_setotherxattr(struct dentry *dentry, char *name) | ||
2301 | { | ||
2302 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | ||
2303 | sizeof XATTR_SECURITY_PREFIX - 1)) { | ||
2304 | if (!strcmp(name, XATTR_NAME_CAPS)) { | ||
2305 | if (!capable(CAP_SETFCAP)) | ||
2306 | return -EPERM; | ||
2307 | } else if (!capable(CAP_SYS_ADMIN)) { | ||
2308 | /* A different attribute in the security namespace. | ||
2309 | Restrict to administrator. */ | ||
2310 | return -EPERM; | ||
2311 | } | ||
2312 | } | ||
2313 | |||
2314 | /* Not an attribute we recognize, so just check the | ||
2315 | ordinary setattr permission. */ | ||
2316 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); | ||
2317 | } | ||
2318 | |||
2300 | static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags) | 2319 | static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags) |
2301 | { | 2320 | { |
2302 | struct task_security_struct *tsec = current->security; | 2321 | struct task_security_struct *tsec = current->security; |
@@ -2307,19 +2326,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value | |||
2307 | u32 newsid; | 2326 | u32 newsid; |
2308 | int rc = 0; | 2327 | int rc = 0; |
2309 | 2328 | ||
2310 | if (strcmp(name, XATTR_NAME_SELINUX)) { | 2329 | if (strcmp(name, XATTR_NAME_SELINUX)) |
2311 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 2330 | return selinux_inode_setotherxattr(dentry, name); |
2312 | sizeof XATTR_SECURITY_PREFIX - 1) && | ||
2313 | !capable(CAP_SYS_ADMIN)) { | ||
2314 | /* A different attribute in the security namespace. | ||
2315 | Restrict to administrator. */ | ||
2316 | return -EPERM; | ||
2317 | } | ||
2318 | |||
2319 | /* Not an attribute we recognize, so just check the | ||
2320 | ordinary setattr permission. */ | ||
2321 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); | ||
2322 | } | ||
2323 | 2331 | ||
2324 | sbsec = inode->i_sb->s_security; | 2332 | sbsec = inode->i_sb->s_security; |
2325 | if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) | 2333 | if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) |
@@ -2393,20 +2401,8 @@ static int selinux_inode_listxattr (struct dentry *dentry) | |||
2393 | 2401 | ||
2394 | static int selinux_inode_removexattr (struct dentry *dentry, char *name) | 2402 | static int selinux_inode_removexattr (struct dentry *dentry, char *name) |
2395 | { | 2403 | { |
2396 | if (strcmp(name, XATTR_NAME_SELINUX)) { | 2404 | if (strcmp(name, XATTR_NAME_SELINUX)) |
2397 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 2405 | return selinux_inode_setotherxattr(dentry, name); |
2398 | sizeof XATTR_SECURITY_PREFIX - 1) && | ||
2399 | !capable(CAP_SYS_ADMIN)) { | ||
2400 | /* A different attribute in the security namespace. | ||
2401 | Restrict to administrator. */ | ||
2402 | return -EPERM; | ||
2403 | } | ||
2404 | |||
2405 | /* Not an attribute we recognize, so just check the | ||
2406 | ordinary setattr permission. Might want a separate | ||
2407 | permission for removexattr. */ | ||
2408 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); | ||
2409 | } | ||
2410 | 2406 | ||
2411 | /* No one is allowed to remove a SELinux security label. | 2407 | /* No one is allowed to remove a SELinux security label. |
2412 | You can change the label, but all data must be labeled. */ | 2408 | You can change the label, but all data must be labeled. */ |
@@ -2464,6 +2460,16 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t | |||
2464 | return len; | 2460 | return len; |
2465 | } | 2461 | } |
2466 | 2462 | ||
2463 | static int selinux_inode_need_killpriv(struct dentry *dentry) | ||
2464 | { | ||
2465 | return secondary_ops->inode_need_killpriv(dentry); | ||
2466 | } | ||
2467 | |||
2468 | static int selinux_inode_killpriv(struct dentry *dentry) | ||
2469 | { | ||
2470 | return secondary_ops->inode_killpriv(dentry); | ||
2471 | } | ||
2472 | |||
2467 | /* file security operations */ | 2473 | /* file security operations */ |
2468 | 2474 | ||
2469 | static int selinux_revalidate_file_permission(struct file *file, int mask) | 2475 | static int selinux_revalidate_file_permission(struct file *file, int mask) |
@@ -2882,6 +2888,12 @@ static int selinux_task_setnice(struct task_struct *p, int nice) | |||
2882 | 2888 | ||
2883 | static int selinux_task_setioprio(struct task_struct *p, int ioprio) | 2889 | static int selinux_task_setioprio(struct task_struct *p, int ioprio) |
2884 | { | 2890 | { |
2891 | int rc; | ||
2892 | |||
2893 | rc = secondary_ops->task_setioprio(p, ioprio); | ||
2894 | if (rc) | ||
2895 | return rc; | ||
2896 | |||
2885 | return task_has_perm(current, p, PROCESS__SETSCHED); | 2897 | return task_has_perm(current, p, PROCESS__SETSCHED); |
2886 | } | 2898 | } |
2887 | 2899 | ||
@@ -2911,6 +2923,12 @@ static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim | |||
2911 | 2923 | ||
2912 | static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) | 2924 | static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) |
2913 | { | 2925 | { |
2926 | int rc; | ||
2927 | |||
2928 | rc = secondary_ops->task_setscheduler(p, policy, lp); | ||
2929 | if (rc) | ||
2930 | return rc; | ||
2931 | |||
2914 | return task_has_perm(current, p, PROCESS__SETSCHED); | 2932 | return task_has_perm(current, p, PROCESS__SETSCHED); |
2915 | } | 2933 | } |
2916 | 2934 | ||
@@ -4830,6 +4848,8 @@ static struct security_operations selinux_ops = { | |||
4830 | .inode_getsecurity = selinux_inode_getsecurity, | 4848 | .inode_getsecurity = selinux_inode_getsecurity, |
4831 | .inode_setsecurity = selinux_inode_setsecurity, | 4849 | .inode_setsecurity = selinux_inode_setsecurity, |
4832 | .inode_listsecurity = selinux_inode_listsecurity, | 4850 | .inode_listsecurity = selinux_inode_listsecurity, |
4851 | .inode_need_killpriv = selinux_inode_need_killpriv, | ||
4852 | .inode_killpriv = selinux_inode_killpriv, | ||
4833 | 4853 | ||
4834 | .file_permission = selinux_file_permission, | 4854 | .file_permission = selinux_file_permission, |
4835 | .file_alloc_security = selinux_file_alloc_security, | 4855 | .file_alloc_security = selinux_file_alloc_security, |