Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull namespace changes from Eric Biederman: "This is an assorted mishmash of small cleanups, enhancements and bug fixes. The major theme is user namespace mount restrictions. nsown_capable is killed as it encourages not thinking about details that need to be considered. A very hard to hit pid namespace exiting bug was finally tracked and fixed. A couple of cleanups to the basic namespace infrastructure. Finally there is an enhancement that makes per user namespace capabilities usable as capabilities, and an enhancement that allows the per userns root to nice other processes in the user namespace" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: userns: Kill nsown_capable it makes the wrong thing easy capabilities: allow nice if we are privileged pidns: Don't have unshare(CLONE_NEWPID) imply CLONE_THREAD userns: Allow PR_CAPBSET_DROP in a user namespace. namespaces: Simplify copy_namespaces so it is clear what is going on. pidns: Fix hang in zap_pid_ns_processes by sending a potentially extra wakeup sysfs: Restrict mounting sysfs userns: Better restrictions on when proc and sysfs can be mounted vfs: Don't copy mount bind mounts of /proc/<pid>/ns/mnt between namespaces kernel/nsproxy.c: Improving a snippet of code. proc: Restrict mounting the proc filesystem vfs: Lock in place mounts from more privileged users
This commit is contained in:
@@ -432,18 +432,6 @@ bool capable(int cap)
|
||||
}
|
||||
EXPORT_SYMBOL(capable);
|
||||
|
||||
/**
|
||||
* nsown_capable - Check superior capability to one's own user_ns
|
||||
* @cap: The capability in question
|
||||
*
|
||||
* Return true if the current task has the given superior capability
|
||||
* targeted at its own user namespace.
|
||||
*/
|
||||
bool nsown_capable(int cap)
|
||||
{
|
||||
return ns_capable(current_user_ns(), cap);
|
||||
}
|
||||
|
||||
/**
|
||||
* inode_capable - Check superior capability over inode
|
||||
* @inode: The inode in question
|
||||
|
||||
@@ -1824,11 +1824,6 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
|
||||
*/
|
||||
if (unshare_flags & CLONE_NEWUSER)
|
||||
unshare_flags |= CLONE_THREAD | CLONE_FS;
|
||||
/*
|
||||
* If unsharing a pid namespace must also unshare the thread.
|
||||
*/
|
||||
if (unshare_flags & CLONE_NEWPID)
|
||||
unshare_flags |= CLONE_THREAD;
|
||||
/*
|
||||
* If unsharing a thread from a thread group, must also unshare vm.
|
||||
*/
|
||||
|
||||
@@ -233,7 +233,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
|
||||
struct group_info *group_info;
|
||||
int retval;
|
||||
|
||||
if (!nsown_capable(CAP_SETGID))
|
||||
if (!ns_capable(current_user_ns(), CAP_SETGID))
|
||||
return -EPERM;
|
||||
if ((unsigned)gidsetsize > NGROUPS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -126,22 +126,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
|
||||
struct nsproxy *old_ns = tsk->nsproxy;
|
||||
struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
|
||||
struct nsproxy *new_ns;
|
||||
int err = 0;
|
||||
|
||||
if (!old_ns)
|
||||
if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
|
||||
CLONE_NEWPID | CLONE_NEWNET)))) {
|
||||
get_nsproxy(old_ns);
|
||||
return 0;
|
||||
|
||||
get_nsproxy(old_ns);
|
||||
|
||||
if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
|
||||
CLONE_NEWPID | CLONE_NEWNET)))
|
||||
return 0;
|
||||
|
||||
if (!ns_capable(user_ns, CAP_SYS_ADMIN)) {
|
||||
err = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
* CLONE_NEWIPC must detach from the undolist: after switching
|
||||
* to a new ipc namespace, the semaphore arrays from the old
|
||||
@@ -149,22 +143,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
|
||||
* means share undolist with parent, so we must forbid using
|
||||
* it along with CLONE_NEWIPC.
|
||||
*/
|
||||
if ((flags & CLONE_NEWIPC) && (flags & CLONE_SYSVSEM)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==
|
||||
(CLONE_NEWIPC | CLONE_SYSVSEM))
|
||||
return -EINVAL;
|
||||
|
||||
new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);
|
||||
if (IS_ERR(new_ns)) {
|
||||
err = PTR_ERR(new_ns);
|
||||
goto out;
|
||||
}
|
||||
if (IS_ERR(new_ns))
|
||||
return PTR_ERR(new_ns);
|
||||
|
||||
tsk->nsproxy = new_ns;
|
||||
|
||||
out:
|
||||
put_nsproxy(old_ns);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_nsproxy(struct nsproxy *ns)
|
||||
|
||||
@@ -265,6 +265,7 @@ void free_pid(struct pid *pid)
|
||||
struct pid_namespace *ns = upid->ns;
|
||||
hlist_del_rcu(&upid->pid_chain);
|
||||
switch(--ns->nr_hashed) {
|
||||
case 2:
|
||||
case 1:
|
||||
/* When all that is left in the pid namespace
|
||||
* is the reaper wake up the reaper. The reaper
|
||||
|
||||
@@ -329,7 +329,7 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns)
|
||||
struct pid_namespace *ancestor, *new = ns;
|
||||
|
||||
if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) ||
|
||||
!nsown_capable(CAP_SYS_ADMIN))
|
||||
!ns_capable(current_user_ns(), CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
|
||||
20
kernel/sys.c
20
kernel/sys.c
@@ -337,7 +337,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
|
||||
if (rgid != (gid_t) -1) {
|
||||
if (gid_eq(old->gid, krgid) ||
|
||||
gid_eq(old->egid, krgid) ||
|
||||
nsown_capable(CAP_SETGID))
|
||||
ns_capable(old->user_ns, CAP_SETGID))
|
||||
new->gid = krgid;
|
||||
else
|
||||
goto error;
|
||||
@@ -346,7 +346,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
|
||||
if (gid_eq(old->gid, kegid) ||
|
||||
gid_eq(old->egid, kegid) ||
|
||||
gid_eq(old->sgid, kegid) ||
|
||||
nsown_capable(CAP_SETGID))
|
||||
ns_capable(old->user_ns, CAP_SETGID))
|
||||
new->egid = kegid;
|
||||
else
|
||||
goto error;
|
||||
@@ -387,7 +387,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
|
||||
old = current_cred();
|
||||
|
||||
retval = -EPERM;
|
||||
if (nsown_capable(CAP_SETGID))
|
||||
if (ns_capable(old->user_ns, CAP_SETGID))
|
||||
new->gid = new->egid = new->sgid = new->fsgid = kgid;
|
||||
else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
|
||||
new->egid = new->fsgid = kgid;
|
||||
@@ -471,7 +471,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
|
||||
new->uid = kruid;
|
||||
if (!uid_eq(old->uid, kruid) &&
|
||||
!uid_eq(old->euid, kruid) &&
|
||||
!nsown_capable(CAP_SETUID))
|
||||
!ns_capable(old->user_ns, CAP_SETUID))
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -480,7 +480,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
|
||||
if (!uid_eq(old->uid, keuid) &&
|
||||
!uid_eq(old->euid, keuid) &&
|
||||
!uid_eq(old->suid, keuid) &&
|
||||
!nsown_capable(CAP_SETUID))
|
||||
!ns_capable(old->user_ns, CAP_SETUID))
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -534,7 +534,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
|
||||
old = current_cred();
|
||||
|
||||
retval = -EPERM;
|
||||
if (nsown_capable(CAP_SETUID)) {
|
||||
if (ns_capable(old->user_ns, CAP_SETUID)) {
|
||||
new->suid = new->uid = kuid;
|
||||
if (!uid_eq(kuid, old->uid)) {
|
||||
retval = set_user(new);
|
||||
@@ -591,7 +591,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
|
||||
old = current_cred();
|
||||
|
||||
retval = -EPERM;
|
||||
if (!nsown_capable(CAP_SETUID)) {
|
||||
if (!ns_capable(old->user_ns, CAP_SETUID)) {
|
||||
if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) &&
|
||||
!uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid))
|
||||
goto error;
|
||||
@@ -673,7 +673,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
|
||||
old = current_cred();
|
||||
|
||||
retval = -EPERM;
|
||||
if (!nsown_capable(CAP_SETGID)) {
|
||||
if (!ns_capable(old->user_ns, CAP_SETGID)) {
|
||||
if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) &&
|
||||
!gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid))
|
||||
goto error;
|
||||
@@ -744,7 +744,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
|
||||
|
||||
if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) ||
|
||||
uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
|
||||
nsown_capable(CAP_SETUID)) {
|
||||
ns_capable(old->user_ns, CAP_SETUID)) {
|
||||
if (!uid_eq(kuid, old->fsuid)) {
|
||||
new->fsuid = kuid;
|
||||
if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
|
||||
@@ -783,7 +783,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
|
||||
|
||||
if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) ||
|
||||
gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
|
||||
nsown_capable(CAP_SETGID)) {
|
||||
ns_capable(old->user_ns, CAP_SETGID)) {
|
||||
if (!gid_eq(kgid, old->fsgid)) {
|
||||
new->fsgid = kgid;
|
||||
goto change_okay;
|
||||
|
||||
@@ -176,7 +176,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)
|
||||
struct group_info *group_info;
|
||||
int retval;
|
||||
|
||||
if (!nsown_capable(CAP_SETGID))
|
||||
if (!ns_capable(current_user_ns(), CAP_SETGID))
|
||||
return -EPERM;
|
||||
if ((unsigned)gidsetsize > NGROUPS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -51,8 +51,6 @@ struct user_namespace init_user_ns = {
|
||||
.owner = GLOBAL_ROOT_UID,
|
||||
.group = GLOBAL_ROOT_GID,
|
||||
.proc_inum = PROC_USER_INIT_INO,
|
||||
.may_mount_sysfs = true,
|
||||
.may_mount_proc = true,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(init_user_ns);
|
||||
|
||||
|
||||
@@ -101,8 +101,6 @@ int create_user_ns(struct cred *new)
|
||||
|
||||
set_cred_user_ns(new, ns);
|
||||
|
||||
update_mnt_policy(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
|
||||
struct uts_namespace *ns = new;
|
||||
|
||||
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
|
||||
!nsown_capable(CAP_SYS_ADMIN))
|
||||
!ns_capable(current_user_ns(), CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
get_uts_ns(ns);
|
||||
|
||||
Reference in New Issue
Block a user