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 <gaofeng@cn.fujitsu.com>

Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
This commit is contained in:
Eric W. Biederman 2012-07-26 06:24:06 -07:00
parent 4c44aaafa8
commit cde1975bc2
3 changed files with 78 additions and 17 deletions

View File

@ -11,6 +11,7 @@
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <linux/ipc_namespace.h> #include <linux/ipc_namespace.h>
#include <linux/pid_namespace.h> #include <linux/pid_namespace.h>
#include <linux/user_namespace.h>
#include "internal.h" #include "internal.h"
@ -26,6 +27,9 @@ static const struct proc_ns_operations *ns_entries[] = {
#endif #endif
#ifdef CONFIG_PID_NS #ifdef CONFIG_PID_NS
&pidns_operations, &pidns_operations,
#endif
#ifdef CONFIG_USER_NS
&userns_operations,
#endif #endif
&mntns_operations, &mntns_operations,
}; };

View File

@ -258,6 +258,7 @@ extern const struct proc_ns_operations netns_operations;
extern const struct proc_ns_operations utsns_operations; extern const struct proc_ns_operations utsns_operations;
extern const struct proc_ns_operations ipcns_operations; extern const struct proc_ns_operations ipcns_operations;
extern const struct proc_ns_operations pidns_operations; extern const struct proc_ns_operations pidns_operations;
extern const struct proc_ns_operations userns_operations;
extern const struct proc_ns_operations mntns_operations; extern const struct proc_ns_operations mntns_operations;
union proc_op { union proc_op {

View File

@ -9,6 +9,7 @@
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/user_namespace.h> #include <linux/user_namespace.h>
#include <linux/proc_fs.h>
#include <linux/highuid.h> #include <linux/highuid.h>
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/securebits.h> #include <linux/securebits.h>
@ -26,6 +27,24 @@ static struct kmem_cache *user_ns_cachep __read_mostly;
static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
struct uid_gid_map *map); struct uid_gid_map *map);
static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
{
/* Start with the same capabilities as init but useless for doing
* anything as the capabilities are bound to the new user namespace.
*/
cred->securebits = SECUREBITS_DEFAULT;
cred->cap_inheritable = CAP_EMPTY_SET;
cred->cap_permitted = CAP_FULL_SET;
cred->cap_effective = CAP_FULL_SET;
cred->cap_bset = CAP_FULL_SET;
#ifdef CONFIG_KEYS
key_put(cred->request_key_auth);
cred->request_key_auth = NULL;
#endif
/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
cred->user_ns = user_ns;
}
/* /*
* Create a new user namespace, deriving the creator from the user in the * Create a new user namespace, deriving the creator from the user in the
* passed credentials, and replacing that user with the new root user for the * passed credentials, and replacing that user with the new root user for the
@ -53,27 +72,12 @@ int create_user_ns(struct cred *new)
return -ENOMEM; return -ENOMEM;
kref_init(&ns->kref); kref_init(&ns->kref);
/* Leave the new->user_ns reference with the new user namespace. */
ns->parent = parent_ns; ns->parent = parent_ns;
ns->owner = owner; ns->owner = owner;
ns->group = group; ns->group = group;
/* Start with the same capabilities as init but useless for doing set_cred_user_ns(new, ns);
* anything as the capabilities are bound to the new user namespace.
*/
new->securebits = SECUREBITS_DEFAULT;
new->cap_inheritable = CAP_EMPTY_SET;
new->cap_permitted = CAP_FULL_SET;
new->cap_effective = CAP_FULL_SET;
new->cap_bset = CAP_FULL_SET;
#ifdef CONFIG_KEYS
key_put(new->request_key_auth);
new->request_key_auth = NULL;
#endif
/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
/* Leave the new->user_ns reference with the new user namespace. */
/* Leave the reference to our user_ns with the new cred. */
new->user_ns = ns;
return 0; return 0;
} }
@ -737,6 +741,58 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
return false; return false;
} }
static void *userns_get(struct task_struct *task)
{
struct user_namespace *user_ns;
rcu_read_lock();
user_ns = get_user_ns(__task_cred(task)->user_ns);
rcu_read_unlock();
return user_ns;
}
static void userns_put(void *ns)
{
put_user_ns(ns);
}
static int userns_install(struct nsproxy *nsproxy, void *ns)
{
struct user_namespace *user_ns = ns;
struct cred *cred;
/* Don't allow gaining capabilities by reentering
* the same user namespace.
*/
if (user_ns == current_user_ns())
return -EINVAL;
/* Threaded many not enter a different user namespace */
if (atomic_read(&current->mm->mm_users) > 1)
return -EINVAL;
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
return -EPERM;
cred = prepare_creds();
if (!cred)
return -ENOMEM;
put_user_ns(cred->user_ns);
set_cred_user_ns(cred, get_user_ns(user_ns));
return commit_creds(cred);
}
const struct proc_ns_operations userns_operations = {
.name = "user",
.type = CLONE_NEWUSER,
.get = userns_get,
.put = userns_put,
.install = userns_install,
};
static __init int user_namespaces_init(void) static __init int user_namespaces_init(void)
{ {
user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC); user_ns_cachep = KMEM_CACHE(user_namespace, SLAB_PANIC);