Skip to content

Commit a2b4262

Browse files
committed
userns,pidns: Verify the userns for new pid namespaces
It is pointless and confusing to allow a pid namespace hierarchy and the user namespace hierarchy to get out of sync. The owner of a child pid namespace should be the owner of the parent pid namespace or a descendant of the owner of the parent pid namespace. Otherwise it is possible to construct scenarios where a process has a capability over a parent pid namespace but does not have the capability over a child pid namespace. Which confusingly makes permission checks non-transitive. It requires use of setns into a pid namespace (but not into a user namespace) to create such a scenario. Add the function in_userns to help in making this determination. v2: Optimized in_userns by using level as suggested by: Kirill Tkhai <[email protected]> Ref: 49f4d8b ("pidns: Capture the user namespace and filter ns_last_pid") Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent 5771a8c commit a2b4262

File tree

3 files changed

+24
-9
lines changed

3 files changed

+24
-9
lines changed

include/linux/user_namespace.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t,
112112
extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *);
113113
extern int proc_setgroups_show(struct seq_file *m, void *v);
114114
extern bool userns_may_setgroups(const struct user_namespace *ns);
115+
extern bool in_userns(const struct user_namespace *ancestor,
116+
const struct user_namespace *child);
115117
extern bool current_in_userns(const struct user_namespace *target_ns);
116-
117118
struct ns_common *ns_get_owner(struct ns_common *ns);
118119
#else
119120

@@ -144,6 +145,12 @@ static inline bool userns_may_setgroups(const struct user_namespace *ns)
144145
return true;
145146
}
146147

148+
static inline bool in_userns(const struct user_namespace *ancestor,
149+
const struct user_namespace *child)
150+
{
151+
return true;
152+
}
153+
147154
static inline bool current_in_userns(const struct user_namespace *target_ns)
148155
{
149156
return true;

kernel/pid_namespace.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
101101
int i;
102102
int err;
103103

104+
err = -EINVAL;
105+
if (!in_userns(parent_pid_ns->user_ns, user_ns))
106+
goto out;
107+
104108
err = -ENOSPC;
105109
if (level > MAX_PID_NS_LEVEL)
106110
goto out;

kernel/user_namespace.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -986,17 +986,21 @@ bool userns_may_setgroups(const struct user_namespace *ns)
986986
}
987987

988988
/*
989-
* Returns true if @ns is the same namespace as or a descendant of
990-
* @target_ns.
989+
* Returns true if @child is the same namespace or a descendant of
990+
* @ancestor.
991991
*/
992+
bool in_userns(const struct user_namespace *ancestor,
993+
const struct user_namespace *child)
994+
{
995+
const struct user_namespace *ns;
996+
for (ns = child; ns->level > ancestor->level; ns = ns->parent)
997+
;
998+
return (ns == ancestor);
999+
}
1000+
9921001
bool current_in_userns(const struct user_namespace *target_ns)
9931002
{
994-
struct user_namespace *ns;
995-
for (ns = current_user_ns(); ns; ns = ns->parent) {
996-
if (ns == target_ns)
997-
return true;
998-
}
999-
return false;
1003+
return in_userns(target_ns, current_user_ns());
10001004
}
10011005

10021006
static inline struct user_namespace *to_user_ns(struct ns_common *ns)

0 commit comments

Comments
 (0)