mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-17 20:44:37 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull (again) user namespace infrastructure changes from Eric Biederman: "Those bugs, those darn embarrasing bugs just want don't want to get fixed. Linus I just updated my mirror of your kernel.org tree and it appears you successfully pulled everything except the last 4 commits that fix those embarrasing bugs. When you get a chance can you please repull my branch" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: userns: Fix typo in description of the limitation of userns_install userns: Add a more complete capability subset test to commit_creds userns: Require CAP_SYS_ADMIN for most uses of setns. Fix cap_capable to only allow owners in the parent user namespace to have caps.
This commit is contained in:
commit
a2faf2fc53
8 changed files with 54 additions and 15 deletions
|
@ -2781,7 +2781,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
|
||||||
struct path root;
|
struct path root;
|
||||||
|
|
||||||
if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
|
if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
|
||||||
!nsown_capable(CAP_SYS_CHROOT))
|
!nsown_capable(CAP_SYS_CHROOT) ||
|
||||||
|
!nsown_capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (fs->users != 1)
|
if (fs->users != 1)
|
||||||
|
|
|
@ -170,7 +170,8 @@ static void ipcns_put(void *ns)
|
||||||
static int ipcns_install(struct nsproxy *nsproxy, void *new)
|
static int ipcns_install(struct nsproxy *nsproxy, void *new)
|
||||||
{
|
{
|
||||||
struct ipc_namespace *ns = new;
|
struct ipc_namespace *ns = new;
|
||||||
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
|
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
|
||||||
|
!nsown_capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
/* Ditch state from the old ipc namespace */
|
/* Ditch state from the old ipc namespace */
|
||||||
|
|
|
@ -372,6 +372,31 @@ error_put:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cred_cap_issubset(const struct cred *set, const struct cred *subset)
|
||||||
|
{
|
||||||
|
const struct user_namespace *set_ns = set->user_ns;
|
||||||
|
const struct user_namespace *subset_ns = subset->user_ns;
|
||||||
|
|
||||||
|
/* If the two credentials are in the same user namespace see if
|
||||||
|
* the capabilities of subset are a subset of set.
|
||||||
|
*/
|
||||||
|
if (set_ns == subset_ns)
|
||||||
|
return cap_issubset(subset->cap_permitted, set->cap_permitted);
|
||||||
|
|
||||||
|
/* The credentials are in a different user namespaces
|
||||||
|
* therefore one is a subset of the other only if a set is an
|
||||||
|
* ancestor of subset and set->euid is owner of subset or one
|
||||||
|
* of subsets ancestors.
|
||||||
|
*/
|
||||||
|
for (;subset_ns != &init_user_ns; subset_ns = subset_ns->parent) {
|
||||||
|
if ((set_ns == subset_ns->parent) &&
|
||||||
|
uid_eq(subset_ns->owner, set->euid))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* commit_creds - Install new credentials upon the current task
|
* commit_creds - Install new credentials upon the current task
|
||||||
* @new: The credentials to be assigned
|
* @new: The credentials to be assigned
|
||||||
|
@ -410,7 +435,7 @@ int commit_creds(struct cred *new)
|
||||||
!gid_eq(old->egid, new->egid) ||
|
!gid_eq(old->egid, new->egid) ||
|
||||||
!uid_eq(old->fsuid, new->fsuid) ||
|
!uid_eq(old->fsuid, new->fsuid) ||
|
||||||
!gid_eq(old->fsgid, new->fsgid) ||
|
!gid_eq(old->fsgid, new->fsgid) ||
|
||||||
!cap_issubset(new->cap_permitted, old->cap_permitted)) {
|
!cred_cap_issubset(old, new)) {
|
||||||
if (task->mm)
|
if (task->mm)
|
||||||
set_dumpable(task->mm, suid_dumpable);
|
set_dumpable(task->mm, suid_dumpable);
|
||||||
task->pdeath_signal = 0;
|
task->pdeath_signal = 0;
|
||||||
|
|
|
@ -325,7 +325,8 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns)
|
||||||
struct pid_namespace *active = task_active_pid_ns(current);
|
struct pid_namespace *active = task_active_pid_ns(current);
|
||||||
struct pid_namespace *ancestor, *new = ns;
|
struct pid_namespace *ancestor, *new = ns;
|
||||||
|
|
||||||
if (!ns_capable(new->user_ns, CAP_SYS_ADMIN))
|
if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) ||
|
||||||
|
!nsown_capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -799,7 +799,7 @@ static int userns_install(struct nsproxy *nsproxy, void *ns)
|
||||||
if (user_ns == current_user_ns())
|
if (user_ns == current_user_ns())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Threaded many not enter a different user namespace */
|
/* Threaded processes may not enter a different user namespace */
|
||||||
if (atomic_read(¤t->mm->mm_users) > 1)
|
if (atomic_read(¤t->mm->mm_users) > 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,8 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
|
||||||
{
|
{
|
||||||
struct uts_namespace *ns = new;
|
struct uts_namespace *ns = new;
|
||||||
|
|
||||||
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
|
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
|
||||||
|
!nsown_capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
get_uts_ns(ns);
|
get_uts_ns(ns);
|
||||||
|
|
|
@ -649,7 +649,8 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
|
||||||
{
|
{
|
||||||
struct net *net = ns;
|
struct net *net = ns;
|
||||||
|
|
||||||
if (!ns_capable(net->user_ns, CAP_SYS_ADMIN))
|
if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) ||
|
||||||
|
!nsown_capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
put_net(nsproxy->net_ns);
|
put_net(nsproxy->net_ns);
|
||||||
|
|
|
@ -76,24 +76,33 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
|
||||||
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
||||||
int cap, int audit)
|
int cap, int audit)
|
||||||
{
|
{
|
||||||
for (;;) {
|
struct user_namespace *ns = targ_ns;
|
||||||
/* The owner of the user namespace has all caps. */
|
|
||||||
if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
/* See if cred has the capability in the target user namespace
|
||||||
|
* by examining the target user namespace and all of the target
|
||||||
|
* user namespace's parents.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
/* Do we have the necessary capabilities? */
|
/* Do we have the necessary capabilities? */
|
||||||
if (targ_ns == cred->user_ns)
|
if (ns == cred->user_ns)
|
||||||
return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
|
return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
|
||||||
|
|
||||||
/* Have we tried all of the parent namespaces? */
|
/* Have we tried all of the parent namespaces? */
|
||||||
if (targ_ns == &init_user_ns)
|
if (ns == &init_user_ns)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The owner of the user namespace in the parent of the
|
||||||
|
* user namespace has all caps.
|
||||||
|
*/
|
||||||
|
if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*If you have a capability in a parent user ns, then you have
|
* If you have a capability in a parent user ns, then you have
|
||||||
* it over all children user namespaces as well.
|
* it over all children user namespaces as well.
|
||||||
*/
|
*/
|
||||||
targ_ns = targ_ns->parent;
|
ns = ns->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We never get here */
|
/* We never get here */
|
||||||
|
|
Loading…
Add table
Reference in a new issue