diff options
| -rw-r--r-- | fs/exec.c | 19 | ||||
| -rw-r--r-- | include/linux/capability.h | 1 | ||||
| -rw-r--r-- | kernel/capability.c | 16 |
3 files changed, 32 insertions, 4 deletions
| @@ -1275,8 +1275,22 @@ EXPORT_SYMBOL(flush_old_exec); | |||
| 1275 | 1275 | ||
| 1276 | void would_dump(struct linux_binprm *bprm, struct file *file) | 1276 | void would_dump(struct linux_binprm *bprm, struct file *file) |
| 1277 | { | 1277 | { |
| 1278 | if (inode_permission(file_inode(file), MAY_READ) < 0) | 1278 | struct inode *inode = file_inode(file); |
| 1279 | if (inode_permission(inode, MAY_READ) < 0) { | ||
| 1280 | struct user_namespace *old, *user_ns; | ||
| 1279 | bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; | 1281 | bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; |
| 1282 | |||
| 1283 | /* Ensure mm->user_ns contains the executable */ | ||
| 1284 | user_ns = old = bprm->mm->user_ns; | ||
| 1285 | while ((user_ns != &init_user_ns) && | ||
| 1286 | !privileged_wrt_inode_uidgid(user_ns, inode)) | ||
| 1287 | user_ns = user_ns->parent; | ||
| 1288 | |||
| 1289 | if (old != user_ns) { | ||
| 1290 | bprm->mm->user_ns = get_user_ns(user_ns); | ||
| 1291 | put_user_ns(old); | ||
| 1292 | } | ||
| 1293 | } | ||
| 1280 | } | 1294 | } |
| 1281 | EXPORT_SYMBOL(would_dump); | 1295 | EXPORT_SYMBOL(would_dump); |
| 1282 | 1296 | ||
| @@ -1306,7 +1320,6 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
| 1306 | !gid_eq(bprm->cred->gid, current_egid())) { | 1320 | !gid_eq(bprm->cred->gid, current_egid())) { |
| 1307 | current->pdeath_signal = 0; | 1321 | current->pdeath_signal = 0; |
| 1308 | } else { | 1322 | } else { |
| 1309 | would_dump(bprm, bprm->file); | ||
| 1310 | if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) | 1323 | if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) |
| 1311 | set_dumpable(current->mm, suid_dumpable); | 1324 | set_dumpable(current->mm, suid_dumpable); |
| 1312 | } | 1325 | } |
| @@ -1741,6 +1754,8 @@ static int do_execveat_common(int fd, struct filename *filename, | |||
| 1741 | if (retval < 0) | 1754 | if (retval < 0) |
| 1742 | goto out; | 1755 | goto out; |
| 1743 | 1756 | ||
| 1757 | would_dump(bprm, bprm->file); | ||
| 1758 | |||
| 1744 | retval = exec_binprm(bprm); | 1759 | retval = exec_binprm(bprm); |
| 1745 | if (retval < 0) | 1760 | if (retval < 0) |
| 1746 | goto out; | 1761 | goto out; |
diff --git a/include/linux/capability.h b/include/linux/capability.h index d6088e2a7668..6ffb67e10c06 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
| @@ -240,6 +240,7 @@ static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap) | |||
| 240 | return true; | 240 | return true; |
| 241 | } | 241 | } |
| 242 | #endif /* CONFIG_MULTIUSER */ | 242 | #endif /* CONFIG_MULTIUSER */ |
| 243 | extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode); | ||
| 243 | extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); | 244 | extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); |
| 244 | extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); | 245 | extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); |
| 245 | extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns); | 246 | extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns); |
diff --git a/kernel/capability.c b/kernel/capability.c index dfa0e4528b0b..4984e1f552eb 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
| @@ -457,6 +457,19 @@ bool file_ns_capable(const struct file *file, struct user_namespace *ns, | |||
| 457 | EXPORT_SYMBOL(file_ns_capable); | 457 | EXPORT_SYMBOL(file_ns_capable); |
| 458 | 458 | ||
| 459 | /** | 459 | /** |
| 460 | * privileged_wrt_inode_uidgid - Do capabilities in the namespace work over the inode? | ||
| 461 | * @ns: The user namespace in question | ||
| 462 | * @inode: The inode in question | ||
| 463 | * | ||
| 464 | * Return true if the inode uid and gid are within the namespace. | ||
| 465 | */ | ||
| 466 | bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode) | ||
| 467 | { | ||
| 468 | return kuid_has_mapping(ns, inode->i_uid) && | ||
| 469 | kgid_has_mapping(ns, inode->i_gid); | ||
| 470 | } | ||
| 471 | |||
| 472 | /** | ||
| 460 | * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped | 473 | * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped |
| 461 | * @inode: The inode in question | 474 | * @inode: The inode in question |
| 462 | * @cap: The capability in question | 475 | * @cap: The capability in question |
| @@ -469,8 +482,7 @@ bool capable_wrt_inode_uidgid(const struct inode *inode, int cap) | |||
| 469 | { | 482 | { |
| 470 | struct user_namespace *ns = current_user_ns(); | 483 | struct user_namespace *ns = current_user_ns(); |
| 471 | 484 | ||
| 472 | return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) && | 485 | return ns_capable(ns, cap) && privileged_wrt_inode_uidgid(ns, inode); |
| 473 | kgid_has_mapping(ns, inode->i_gid); | ||
| 474 | } | 486 | } |
| 475 | EXPORT_SYMBOL(capable_wrt_inode_uidgid); | 487 | EXPORT_SYMBOL(capable_wrt_inode_uidgid); |
| 476 | 488 | ||
