Skip to content

Commit a2faf2f

Browse files
committed
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.
2 parents 4351654 + 5155040 commit a2faf2f

File tree

8 files changed

+54
-15
lines changed

8 files changed

+54
-15
lines changed

fs/namespace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2781,7 +2781,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
27812781
struct path root;
27822782

27832783
if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
2784-
!nsown_capable(CAP_SYS_CHROOT))
2784+
!nsown_capable(CAP_SYS_CHROOT) ||
2785+
!nsown_capable(CAP_SYS_ADMIN))
27852786
return -EPERM;
27862787

27872788
if (fs->users != 1)

ipc/namespace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ static void ipcns_put(void *ns)
170170
static int ipcns_install(struct nsproxy *nsproxy, void *new)
171171
{
172172
struct ipc_namespace *ns = new;
173-
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
173+
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
174+
!nsown_capable(CAP_SYS_ADMIN))
174175
return -EPERM;
175176

176177
/* Ditch state from the old ipc namespace */

kernel/cred.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,31 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
372372
return ret;
373373
}
374374

375+
static bool cred_cap_issubset(const struct cred *set, const struct cred *subset)
376+
{
377+
const struct user_namespace *set_ns = set->user_ns;
378+
const struct user_namespace *subset_ns = subset->user_ns;
379+
380+
/* If the two credentials are in the same user namespace see if
381+
* the capabilities of subset are a subset of set.
382+
*/
383+
if (set_ns == subset_ns)
384+
return cap_issubset(subset->cap_permitted, set->cap_permitted);
385+
386+
/* The credentials are in a different user namespaces
387+
* therefore one is a subset of the other only if a set is an
388+
* ancestor of subset and set->euid is owner of subset or one
389+
* of subsets ancestors.
390+
*/
391+
for (;subset_ns != &init_user_ns; subset_ns = subset_ns->parent) {
392+
if ((set_ns == subset_ns->parent) &&
393+
uid_eq(subset_ns->owner, set->euid))
394+
return true;
395+
}
396+
397+
return false;
398+
}
399+
375400
/**
376401
* commit_creds - Install new credentials upon the current task
377402
* @new: The credentials to be assigned
@@ -410,7 +435,7 @@ int commit_creds(struct cred *new)
410435
!gid_eq(old->egid, new->egid) ||
411436
!uid_eq(old->fsuid, new->fsuid) ||
412437
!gid_eq(old->fsgid, new->fsgid) ||
413-
!cap_issubset(new->cap_permitted, old->cap_permitted)) {
438+
!cred_cap_issubset(old, new)) {
414439
if (task->mm)
415440
set_dumpable(task->mm, suid_dumpable);
416441
task->pdeath_signal = 0;

kernel/pid_namespace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,8 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns)
325325
struct pid_namespace *active = task_active_pid_ns(current);
326326
struct pid_namespace *ancestor, *new = ns;
327327

328-
if (!ns_capable(new->user_ns, CAP_SYS_ADMIN))
328+
if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) ||
329+
!nsown_capable(CAP_SYS_ADMIN))
329330
return -EPERM;
330331

331332
/*

kernel/user_namespace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ static int userns_install(struct nsproxy *nsproxy, void *ns)
799799
if (user_ns == current_user_ns())
800800
return -EINVAL;
801801

802-
/* Threaded many not enter a different user namespace */
802+
/* Threaded processes may not enter a different user namespace */
803803
if (atomic_read(&current->mm->mm_users) > 1)
804804
return -EINVAL;
805805

kernel/utsname.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
113113
{
114114
struct uts_namespace *ns = new;
115115

116-
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
116+
if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
117+
!nsown_capable(CAP_SYS_ADMIN))
117118
return -EPERM;
118119

119120
get_uts_ns(ns);

net/core/net_namespace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,8 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
649649
{
650650
struct net *net = ns;
651651

652-
if (!ns_capable(net->user_ns, CAP_SYS_ADMIN))
652+
if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) ||
653+
!nsown_capable(CAP_SYS_ADMIN))
653654
return -EPERM;
654655

655656
put_net(nsproxy->net_ns);

security/commoncap.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,24 +76,33 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
7676
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
7777
int cap, int audit)
7878
{
79-
for (;;) {
80-
/* The owner of the user namespace has all caps. */
81-
if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid))
82-
return 0;
79+
struct user_namespace *ns = targ_ns;
8380

81+
/* See if cred has the capability in the target user namespace
82+
* by examining the target user namespace and all of the target
83+
* user namespace's parents.
84+
*/
85+
for (;;) {
8486
/* Do we have the necessary capabilities? */
85-
if (targ_ns == cred->user_ns)
87+
if (ns == cred->user_ns)
8688
return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
8789

8890
/* Have we tried all of the parent namespaces? */
89-
if (targ_ns == &init_user_ns)
91+
if (ns == &init_user_ns)
9092
return -EPERM;
9193

94+
/*
95+
* The owner of the user namespace in the parent of the
96+
* user namespace has all caps.
97+
*/
98+
if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid))
99+
return 0;
100+
92101
/*
93-
*If you have a capability in a parent user ns, then you have
102+
* If you have a capability in a parent user ns, then you have
94103
* it over all children user namespaces as well.
95104
*/
96-
targ_ns = targ_ns->parent;
105+
ns = ns->parent;
97106
}
98107

99108
/* We never get here */

0 commit comments

Comments
 (0)