diff options
Diffstat (limited to 'security/commoncap.c')
-rw-r--r-- | security/commoncap.c | 244 |
1 files changed, 228 insertions, 16 deletions
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); |