Skip to content

Commit cde1975

Browse files
committed
userns: Implent proc namespace operations
This allows entering a user namespace, and the ability to store a reference to a user namespace with a bind mount. Addition of missing userns_ns_put in userns_install from Gao feng <[email protected]> Acked-by: Serge Hallyn <[email protected]> Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent 4c44aaa commit cde1975

File tree

3 files changed

+78
-17
lines changed

3 files changed

+78
-17
lines changed

fs/proc/namespaces.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <net/net_namespace.h>
1212
#include <linux/ipc_namespace.h>
1313
#include <linux/pid_namespace.h>
14+
#include <linux/user_namespace.h>
1415
#include "internal.h"
1516

1617

@@ -26,6 +27,9 @@ static const struct proc_ns_operations *ns_entries[] = {
2627
#endif
2728
#ifdef CONFIG_PID_NS
2829
&pidns_operations,
30+
#endif
31+
#ifdef CONFIG_USER_NS
32+
&userns_operations,
2933
#endif
3034
&mntns_operations,
3135
};

include/linux/proc_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ extern const struct proc_ns_operations netns_operations;
258258
extern const struct proc_ns_operations utsns_operations;
259259
extern const struct proc_ns_operations ipcns_operations;
260260
extern const struct proc_ns_operations pidns_operations;
261+
extern const struct proc_ns_operations userns_operations;
261262
extern const struct proc_ns_operations mntns_operations;
262263

263264
union proc_op {

kernel/user_namespace.c

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/nsproxy.h>
1010
#include <linux/slab.h>
1111
#include <linux/user_namespace.h>
12+
#include <linux/proc_fs.h>
1213
#include <linux/highuid.h>
1314
#include <linux/cred.h>
1415
#include <linux/securebits.h>
@@ -26,6 +27,24 @@ static struct kmem_cache *user_ns_cachep __read_mostly;
2627
static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
2728
struct uid_gid_map *map);
2829

30+
static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
31+
{
32+
/* Start with the same capabilities as init but useless for doing
33+
* anything as the capabilities are bound to the new user namespace.
34+
*/
35+
cred->securebits = SECUREBITS_DEFAULT;
36+
cred->cap_inheritable = CAP_EMPTY_SET;
37+
cred->cap_permitted = CAP_FULL_SET;
38+
cred->cap_effective = CAP_FULL_SET;
39+
cred->cap_bset = CAP_FULL_SET;
40+
#ifdef CONFIG_KEYS
41+
key_put(cred->request_key_auth);
42+
cred->request_key_auth = NULL;
43+
#endif
44+
/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
45+
cred->user_ns = user_ns;
46+
}
47+
2948
/*
3049
* Create a new user namespace, deriving the creator from the user in the
3150
* passed credentials, and replacing that user with the new root user for the
@@ -53,27 +72,12 @@ int create_user_ns(struct cred *new)
5372
return -ENOMEM;
5473

5574
kref_init(&ns->kref);
75+
/* Leave the new->user_ns reference with the new user namespace. */
5676
ns->parent = parent_ns;
5777
ns->owner = owner;
5878
ns->group = group;
5979

60-
/* Start with the same capabilities as init but useless for doing
61-
* anything as the capabilities are bound to the new user namespace.
62-
*/
63-
new->securebits = SECUREBITS_DEFAULT;
64-
new->cap_inheritable = CAP_EMPTY_SET;
65-
new->cap_permitted = CAP_FULL_SET;
66-
new->cap_effective = CAP_FULL_SET;
67-
new->cap_bset = CAP_FULL_SET;
68-
#ifdef CONFIG_KEYS
69-
key_put(new->request_key_auth);
70-
new->request_key_auth = NULL;
71-
#endif
72-
/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
73-
74-
/* Leave the new->user_ns reference with the new user namespace. */
75-
/* Leave the reference to our user_ns with the new cred. */
76-
new->user_ns = ns;
80+
set_cred_user_ns(new, ns);
7781

7882
return 0;
7983
}
@@ -737,6 +741,58 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
737741
return false;
738742
}
739743

744+
static void *userns_get(struct task_struct *task)
745+
{
746+
struct user_namespace *user_ns;
747+
748+
rcu_read_lock();
749+
user_ns = get_user_ns(__task_cred(task)->user_ns);
750+
rcu_read_unlock();
751+
752+
return user_ns;
753+
}
754+
755+
static void userns_put(void *ns)
756+
{
757+
put_user_ns(ns);
758+
}
759+
760+
static int userns_install(struct nsproxy *nsproxy, void *ns)
761+
{
762+
struct user_namespace *user_ns = ns;
763+
struct cred *cred;
764+
765+
/* Don't allow gaining capabilities by reentering
766+
* the same user namespace.
767+
*/
768+
if (user_ns == current_user_ns())
769+
return -EINVAL;
770+
771+
/* Threaded many not enter a different user namespace */
772+
if (atomic_read(&current->mm->mm_users) > 1)
773+
return -EINVAL;
774+
775+
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
776+
return -EPERM;
777+
778+
cred = prepare_creds();
779+
if (!cred)
780+
return -ENOMEM;
781+
782+
put_user_ns(cred->user_ns);
783+
set_cred_user_ns(cred, get_user_ns(user_ns));
784+
785+
return commit_creds(cred);
786+
}
787+
788+
const struct proc_ns_operations userns_operations = {
789+
.name = "user",
790+
.type = CLONE_NEWUSER,
791+
.get = userns_get,
792+
.put = userns_put,
793+
.install = userns_install,
794+
};
795+
740796
static __init int user_namespaces_init(void)
741797
{
742798
user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC);

0 commit comments

Comments
 (0)