提交 3496f92b 编写于 作者: J James Morris

Merge branch 'serge-next' into next

...@@ -360,7 +360,7 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, ...@@ -360,7 +360,7 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
struct ecryptfs_msg_ctx *msg_ctx; struct ecryptfs_msg_ctx *msg_ctx;
size_t msg_size; size_t msg_size;
struct nsproxy *nsproxy; struct nsproxy *nsproxy;
struct user_namespace *current_user_ns; struct user_namespace *tsk_user_ns;
uid_t ctx_euid; uid_t ctx_euid;
int rc; int rc;
...@@ -385,9 +385,9 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, ...@@ -385,9 +385,9 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
mutex_unlock(&ecryptfs_daemon_hash_mux); mutex_unlock(&ecryptfs_daemon_hash_mux);
goto wake_up; goto wake_up;
} }
current_user_ns = nsproxy->user_ns; tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns;
ctx_euid = task_euid(msg_ctx->task); ctx_euid = task_euid(msg_ctx->task);
rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, current_user_ns); rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);
rcu_read_unlock(); rcu_read_unlock();
mutex_unlock(&ecryptfs_daemon_hash_mux); mutex_unlock(&ecryptfs_daemon_hash_mux);
if (rc) { if (rc) {
...@@ -405,11 +405,11 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, ...@@ -405,11 +405,11 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
euid, ctx_euid); euid, ctx_euid);
goto unlock; goto unlock;
} }
if (current_user_ns != user_ns) { if (tsk_user_ns != user_ns) {
rc = -EBADMSG; rc = -EBADMSG;
printk(KERN_WARNING "%s: Received message from user_ns " printk(KERN_WARNING "%s: Received message from user_ns "
"[0x%p]; expected message from user_ns [0x%p]\n", "[0x%p]; expected message from user_ns [0x%p]\n",
__func__, user_ns, nsproxy->user_ns); __func__, user_ns, tsk_user_ns);
goto unlock; goto unlock;
} }
if (daemon->pid != pid) { if (daemon->pid != pid) {
...@@ -468,8 +468,7 @@ ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type, ...@@ -468,8 +468,7 @@ ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
uid_t euid = current_euid(); uid_t euid = current_euid();
int rc; int rc;
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
current->nsproxy->user_ns);
if (rc || !daemon) { if (rc || !daemon) {
rc = -ENOTCONN; rc = -ENOTCONN;
printk(KERN_ERR "%s: User [%d] does not have a daemon " printk(KERN_ERR "%s: User [%d] does not have a daemon "
......
...@@ -47,8 +47,7 @@ ecryptfs_miscdev_poll(struct file *file, poll_table *pt) ...@@ -47,8 +47,7 @@ ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
mutex_lock(&ecryptfs_daemon_hash_mux); mutex_lock(&ecryptfs_daemon_hash_mux);
/* TODO: Just use file->private_data? */ /* TODO: Just use file->private_data? */
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
current->nsproxy->user_ns);
BUG_ON(rc || !daemon); BUG_ON(rc || !daemon);
mutex_lock(&daemon->mux); mutex_lock(&daemon->mux);
mutex_unlock(&ecryptfs_daemon_hash_mux); mutex_unlock(&ecryptfs_daemon_hash_mux);
...@@ -95,11 +94,9 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) ...@@ -95,11 +94,9 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file)
"count; rc = [%d]\n", __func__, rc); "count; rc = [%d]\n", __func__, rc);
goto out_unlock_daemon_list; goto out_unlock_daemon_list;
} }
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
current->nsproxy->user_ns);
if (rc || !daemon) { if (rc || !daemon) {
rc = ecryptfs_spawn_daemon(&daemon, euid, rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(),
current->nsproxy->user_ns,
task_pid(current)); task_pid(current));
if (rc) { if (rc) {
printk(KERN_ERR "%s: Error attempting to spawn daemon; " printk(KERN_ERR "%s: Error attempting to spawn daemon; "
...@@ -153,8 +150,7 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file) ...@@ -153,8 +150,7 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file)
int rc; int rc;
mutex_lock(&ecryptfs_daemon_hash_mux); mutex_lock(&ecryptfs_daemon_hash_mux);
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
current->nsproxy->user_ns);
BUG_ON(rc || !daemon); BUG_ON(rc || !daemon);
mutex_lock(&daemon->mux); mutex_lock(&daemon->mux);
BUG_ON(daemon->pid != task_pid(current)); BUG_ON(daemon->pid != task_pid(current));
...@@ -254,8 +250,7 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, ...@@ -254,8 +250,7 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
mutex_lock(&ecryptfs_daemon_hash_mux); mutex_lock(&ecryptfs_daemon_hash_mux);
/* TODO: Just use file->private_data? */ /* TODO: Just use file->private_data? */
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
current->nsproxy->user_ns);
BUG_ON(rc || !daemon); BUG_ON(rc || !daemon);
mutex_lock(&daemon->mux); mutex_lock(&daemon->mux);
if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
...@@ -295,7 +290,7 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, ...@@ -295,7 +290,7 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
goto check_list; goto check_list;
} }
BUG_ON(euid != daemon->euid); BUG_ON(euid != daemon->euid);
BUG_ON(current->nsproxy->user_ns != daemon->user_ns); BUG_ON(current_user_ns() != daemon->user_ns);
BUG_ON(task_pid(current) != daemon->pid); BUG_ON(task_pid(current) != daemon->pid);
msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue, msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
struct ecryptfs_msg_ctx, daemon_out_list); struct ecryptfs_msg_ctx, daemon_out_list);
...@@ -468,7 +463,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf, ...@@ -468,7 +463,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
goto out_free; goto out_free;
} }
rc = ecryptfs_miscdev_response(&data[i], packet_size, rc = ecryptfs_miscdev_response(&data[i], packet_size,
euid, current->nsproxy->user_ns, euid, current_user_ns(),
task_pid(current), seq); task_pid(current), seq);
if (rc) if (rc)
printk(KERN_WARNING "%s: Failed to deliver miscdev " printk(KERN_WARNING "%s: Failed to deliver miscdev "
......
...@@ -60,6 +60,7 @@ do { \ ...@@ -60,6 +60,7 @@ do { \
} while (0) } while (0)
extern struct group_info *groups_alloc(int); extern struct group_info *groups_alloc(int);
extern struct group_info init_groups;
extern void groups_free(struct group_info *); extern void groups_free(struct group_info *);
extern int set_current_groups(struct group_info *); extern int set_current_groups(struct group_info *);
extern int set_groups(struct cred *, struct group_info *); extern int set_groups(struct cred *, struct group_info *);
...@@ -315,6 +316,7 @@ static inline void put_cred(const struct cred *_cred) ...@@ -315,6 +316,7 @@ static inline void put_cred(const struct cred *_cred)
#define current_fsgid() (current_cred_xxx(fsgid)) #define current_fsgid() (current_cred_xxx(fsgid))
#define current_cap() (current_cred_xxx(cap_effective)) #define current_cap() (current_cred_xxx(cap_effective))
#define current_user() (current_cred_xxx(user)) #define current_user() (current_cred_xxx(user))
#define current_user_ns() (current_cred_xxx(user)->user_ns)
#define current_security() (current_cred_xxx(security)) #define current_security() (current_cred_xxx(security))
#define current_uid_gid(_uid, _gid) \ #define current_uid_gid(_uid, _gid) \
......
...@@ -57,7 +57,6 @@ extern struct nsproxy init_nsproxy; ...@@ -57,7 +57,6 @@ extern struct nsproxy init_nsproxy;
.mnt_ns = NULL, \ .mnt_ns = NULL, \
INIT_NET_NS(net_ns) \ INIT_NET_NS(net_ns) \
INIT_IPC_NS(ipc_ns) \ INIT_IPC_NS(ipc_ns) \
.user_ns = &init_user_ns, \
} }
#define INIT_SIGHAND(sighand) { \ #define INIT_SIGHAND(sighand) { \
......
...@@ -27,7 +27,6 @@ struct nsproxy { ...@@ -27,7 +27,6 @@ struct nsproxy {
struct ipc_namespace *ipc_ns; struct ipc_namespace *ipc_ns;
struct mnt_namespace *mnt_ns; struct mnt_namespace *mnt_ns;
struct pid_namespace *pid_ns; struct pid_namespace *pid_ns;
struct user_namespace *user_ns;
struct net *net_ns; struct net *net_ns;
}; };
extern struct nsproxy init_nsproxy; extern struct nsproxy init_nsproxy;
......
...@@ -638,6 +638,7 @@ struct user_struct { ...@@ -638,6 +638,7 @@ struct user_struct {
/* Hash table maintenance information */ /* Hash table maintenance information */
struct hlist_node uidhash_node; struct hlist_node uidhash_node;
uid_t uid; uid_t uid;
struct user_namespace *user_ns;
#ifdef CONFIG_USER_SCHED #ifdef CONFIG_USER_SCHED
struct task_group *tg; struct task_group *tg;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
struct user_namespace { struct user_namespace {
struct kref kref; struct kref kref;
struct hlist_head uidhash_table[UIDHASH_SZ]; struct hlist_head uidhash_table[UIDHASH_SZ];
struct user_struct *root_user; struct user_struct *creator;
}; };
extern struct user_namespace init_user_ns; extern struct user_namespace init_user_ns;
...@@ -26,8 +26,7 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns) ...@@ -26,8 +26,7 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
return ns; return ns;
} }
extern struct user_namespace *copy_user_ns(int flags, extern int create_user_ns(struct cred *new);
struct user_namespace *old_ns);
extern void free_user_ns(struct kref *kref); extern void free_user_ns(struct kref *kref);
static inline void put_user_ns(struct user_namespace *ns) static inline void put_user_ns(struct user_namespace *ns)
...@@ -43,13 +42,9 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns) ...@@ -43,13 +42,9 @@ static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
return &init_user_ns; return &init_user_ns;
} }
static inline struct user_namespace *copy_user_ns(int flags, static inline int create_user_ns(struct cred *new)
struct user_namespace *old_ns)
{ {
if (flags & CLONE_NEWUSER) return -EINVAL;
return ERR_PTR(-EINVAL);
return old_ns;
} }
static inline void put_user_ns(struct user_namespace *ns) static inline void put_user_ns(struct user_namespace *ns)
......
...@@ -274,6 +274,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) ...@@ -274,6 +274,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
struct thread_group_cred *tgcred; struct thread_group_cred *tgcred;
#endif #endif
struct cred *new; struct cred *new;
int ret;
mutex_init(&p->cred_exec_mutex); mutex_init(&p->cred_exec_mutex);
...@@ -293,6 +294,12 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) ...@@ -293,6 +294,12 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
if (!new) if (!new)
return -ENOMEM; return -ENOMEM;
if (clone_flags & CLONE_NEWUSER) {
ret = create_user_ns(new);
if (ret < 0)
goto error_put;
}
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
/* new threads get their own thread keyrings if their parent already /* new threads get their own thread keyrings if their parent already
* had one */ * had one */
...@@ -309,8 +316,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) ...@@ -309,8 +316,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
if (!(clone_flags & CLONE_THREAD)) { if (!(clone_flags & CLONE_THREAD)) {
tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
if (!tgcred) { if (!tgcred) {
put_cred(new); ret = -ENOMEM;
return -ENOMEM; goto error_put;
} }
atomic_set(&tgcred->usage, 1); atomic_set(&tgcred->usage, 1);
spin_lock_init(&tgcred->lock); spin_lock_init(&tgcred->lock);
...@@ -325,6 +332,10 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) ...@@ -325,6 +332,10 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
atomic_inc(&new->user->processes); atomic_inc(&new->user->processes);
p->cred = p->real_cred = get_cred(new); p->cred = p->real_cred = get_cred(new);
return 0; return 0;
error_put:
put_cred(new);
return ret;
} }
/** /**
......
...@@ -976,7 +976,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -976,7 +976,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
if (atomic_read(&p->real_cred->user->processes) >= if (atomic_read(&p->real_cred->user->processes) >=
p->signal->rlim[RLIMIT_NPROC].rlim_cur) { p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
p->real_cred->user != current->nsproxy->user_ns->root_user) p->real_cred->user != INIT_USER)
goto bad_fork_free; goto bad_fork_free;
} }
...@@ -1334,6 +1334,20 @@ long do_fork(unsigned long clone_flags, ...@@ -1334,6 +1334,20 @@ long do_fork(unsigned long clone_flags,
int trace = 0; int trace = 0;
long nr; long nr;
/*
* Do some preliminary argument and permissions checking before we
* actually start allocating stuff
*/
if (clone_flags & CLONE_NEWUSER) {
if (clone_flags & CLONE_THREAD)
return -EINVAL;
/* hopefully this check will go away when userns support is
* complete
*/
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
}
/* /*
* We hope to recycle these flags after 2.6.26 * We hope to recycle these flags after 2.6.26
*/ */
...@@ -1581,8 +1595,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) ...@@ -1581,8 +1595,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
err = -EINVAL; err = -EINVAL;
if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER| CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))
CLONE_NEWNET))
goto bad_unshare_out; goto bad_unshare_out;
/* /*
......
...@@ -80,12 +80,6 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, ...@@ -80,12 +80,6 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
goto out_pid; goto out_pid;
} }
new_nsp->user_ns = copy_user_ns(flags, tsk->nsproxy->user_ns);
if (IS_ERR(new_nsp->user_ns)) {
err = PTR_ERR(new_nsp->user_ns);
goto out_user;
}
new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns); new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns);
if (IS_ERR(new_nsp->net_ns)) { if (IS_ERR(new_nsp->net_ns)) {
err = PTR_ERR(new_nsp->net_ns); err = PTR_ERR(new_nsp->net_ns);
...@@ -95,9 +89,6 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, ...@@ -95,9 +89,6 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
return new_nsp; return new_nsp;
out_net: out_net:
if (new_nsp->user_ns)
put_user_ns(new_nsp->user_ns);
out_user:
if (new_nsp->pid_ns) if (new_nsp->pid_ns)
put_pid_ns(new_nsp->pid_ns); put_pid_ns(new_nsp->pid_ns);
out_pid: out_pid:
...@@ -130,7 +121,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) ...@@ -130,7 +121,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
get_nsproxy(old_ns); get_nsproxy(old_ns);
if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET))) CLONE_NEWPID | CLONE_NEWNET)))
return 0; return 0;
if (!capable(CAP_SYS_ADMIN)) { if (!capable(CAP_SYS_ADMIN)) {
...@@ -173,8 +164,6 @@ void free_nsproxy(struct nsproxy *ns) ...@@ -173,8 +164,6 @@ void free_nsproxy(struct nsproxy *ns)
put_ipc_ns(ns->ipc_ns); put_ipc_ns(ns->ipc_ns);
if (ns->pid_ns) if (ns->pid_ns)
put_pid_ns(ns->pid_ns); put_pid_ns(ns->pid_ns);
if (ns->user_ns)
put_user_ns(ns->user_ns);
put_net(ns->net_ns); put_net(ns->net_ns);
kmem_cache_free(nsproxy_cachep, ns); kmem_cache_free(nsproxy_cachep, ns);
} }
...@@ -189,7 +178,7 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags, ...@@ -189,7 +178,7 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
int err = 0; int err = 0;
if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
CLONE_NEWUSER | CLONE_NEWNET))) CLONE_NEWNET)))
return 0; return 0;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
......
...@@ -565,13 +565,13 @@ static int set_user(struct cred *new) ...@@ -565,13 +565,13 @@ static int set_user(struct cred *new)
{ {
struct user_struct *new_user; struct user_struct *new_user;
new_user = alloc_uid(current->nsproxy->user_ns, new->uid); new_user = alloc_uid(current_user_ns(), new->uid);
if (!new_user) if (!new_user)
return -EAGAIN; return -EAGAIN;
if (atomic_read(&new_user->processes) >= if (atomic_read(&new_user->processes) >=
current->signal->rlim[RLIMIT_NPROC].rlim_cur && current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
new_user != current->nsproxy->user_ns->root_user) { new_user != INIT_USER) {
free_uid(new_user); free_uid(new_user);
return -EAGAIN; return -EAGAIN;
} }
......
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
struct user_namespace init_user_ns = { struct user_namespace init_user_ns = {
.kref = { .kref = {
.refcount = ATOMIC_INIT(2), .refcount = ATOMIC_INIT(1),
}, },
.root_user = &root_user, .creator = &root_user,
}; };
EXPORT_SYMBOL_GPL(init_user_ns); EXPORT_SYMBOL_GPL(init_user_ns);
...@@ -48,12 +48,14 @@ static struct kmem_cache *uid_cachep; ...@@ -48,12 +48,14 @@ static struct kmem_cache *uid_cachep;
*/ */
static DEFINE_SPINLOCK(uidhash_lock); static DEFINE_SPINLOCK(uidhash_lock);
/* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->creator */
struct user_struct root_user = { struct user_struct root_user = {
.__count = ATOMIC_INIT(1), .__count = ATOMIC_INIT(2),
.processes = ATOMIC_INIT(1), .processes = ATOMIC_INIT(1),
.files = ATOMIC_INIT(0), .files = ATOMIC_INIT(0),
.sigpending = ATOMIC_INIT(0), .sigpending = ATOMIC_INIT(0),
.locked_shm = 0, .locked_shm = 0,
.user_ns = &init_user_ns,
#ifdef CONFIG_USER_SCHED #ifdef CONFIG_USER_SCHED
.tg = &init_task_group, .tg = &init_task_group,
#endif #endif
...@@ -314,12 +316,13 @@ static void remove_user_sysfs_dir(struct work_struct *w) ...@@ -314,12 +316,13 @@ static void remove_user_sysfs_dir(struct work_struct *w)
* IRQ state (as stored in flags) is restored and uidhash_lock released * IRQ state (as stored in flags) is restored and uidhash_lock released
* upon function exit. * upon function exit.
*/ */
static inline void free_user(struct user_struct *up, unsigned long flags) static void free_user(struct user_struct *up, unsigned long flags)
{ {
/* restore back the count */ /* restore back the count */
atomic_inc(&up->__count); atomic_inc(&up->__count);
spin_unlock_irqrestore(&uidhash_lock, flags); spin_unlock_irqrestore(&uidhash_lock, flags);
put_user_ns(up->user_ns);
INIT_WORK(&up->work, remove_user_sysfs_dir); INIT_WORK(&up->work, remove_user_sysfs_dir);
schedule_work(&up->work); schedule_work(&up->work);
} }
...@@ -335,13 +338,14 @@ static inline void uids_mutex_unlock(void) { } ...@@ -335,13 +338,14 @@ static inline void uids_mutex_unlock(void) { }
* IRQ state (as stored in flags) is restored and uidhash_lock released * IRQ state (as stored in flags) is restored and uidhash_lock released
* upon function exit. * upon function exit.
*/ */
static inline void free_user(struct user_struct *up, unsigned long flags) static void free_user(struct user_struct *up, unsigned long flags)
{ {
uid_hash_remove(up); uid_hash_remove(up);
spin_unlock_irqrestore(&uidhash_lock, flags); spin_unlock_irqrestore(&uidhash_lock, flags);
sched_destroy_user(up); sched_destroy_user(up);
key_put(up->uid_keyring); key_put(up->uid_keyring);
key_put(up->session_keyring); key_put(up->session_keyring);
put_user_ns(up->user_ns);
kmem_cache_free(uid_cachep, up); kmem_cache_free(uid_cachep, up);
} }
...@@ -357,7 +361,7 @@ struct user_struct *find_user(uid_t uid) ...@@ -357,7 +361,7 @@ struct user_struct *find_user(uid_t uid)
{ {
struct user_struct *ret; struct user_struct *ret;
unsigned long flags; unsigned long flags;
struct user_namespace *ns = current->nsproxy->user_ns; struct user_namespace *ns = current_user_ns();
spin_lock_irqsave(&uidhash_lock, flags); spin_lock_irqsave(&uidhash_lock, flags);
ret = uid_hash_find(uid, uidhashentry(ns, uid)); ret = uid_hash_find(uid, uidhashentry(ns, uid));
...@@ -404,6 +408,8 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) ...@@ -404,6 +408,8 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
if (sched_create_user(new) < 0) if (sched_create_user(new) < 0)
goto out_free_user; goto out_free_user;
new->user_ns = get_user_ns(ns);
if (uids_user_create(new)) if (uids_user_create(new))
goto out_destoy_sched; goto out_destoy_sched;
...@@ -427,7 +433,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) ...@@ -427,7 +433,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
up = new; up = new;
} }
spin_unlock_irq(&uidhash_lock); spin_unlock_irq(&uidhash_lock);
} }
uids_mutex_unlock(); uids_mutex_unlock();
...@@ -436,6 +441,7 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) ...@@ -436,6 +441,7 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
out_destoy_sched: out_destoy_sched:
sched_destroy_user(new); sched_destroy_user(new);
put_user_ns(new->user_ns);
out_free_user: out_free_user:
kmem_cache_free(uid_cachep, new); kmem_cache_free(uid_cachep, new);
out_unlock: out_unlock:
...@@ -443,33 +449,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid) ...@@ -443,33 +449,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
return NULL; return NULL;
} }
#ifdef CONFIG_USER_NS
void release_uids(struct user_namespace *ns)
{
int i;
unsigned long flags;
struct hlist_head *head;
struct hlist_node *nd;
spin_lock_irqsave(&uidhash_lock, flags);
/*
* collapse the chains so that the user_struct-s will
* be still alive, but not in hashes. subsequent free_uid()
* will free them.
*/
for (i = 0; i < UIDHASH_SZ; i++) {
head = ns->uidhash_table + i;
while (!hlist_empty(head)) {
nd = head->first;
hlist_del_init(nd);
}
}
spin_unlock_irqrestore(&uidhash_lock, flags);
free_uid(ns->root_user);
}
#endif
static int __init uid_cache_init(void) static int __init uid_cache_init(void)
{ {
int n; int n;
......
...@@ -9,70 +9,55 @@ ...@@ -9,70 +9,55 @@
#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/cred.h>
/* /*
* Clone a new ns copying an original user ns, setting refcount to 1 * Create a new user namespace, deriving the creator from the user in the
* @old_ns: namespace to clone * passed credentials, and replacing that user with the new root user for the
* Return NULL on error (failure to kmalloc), new ns otherwise * new namespace.
*
* This is called by copy_creds(), which will finish setting the target task's
* credentials.
*/ */
static struct user_namespace *clone_user_ns(struct user_namespace *old_ns) int create_user_ns(struct cred *new)
{ {
struct user_namespace *ns; struct user_namespace *ns;
struct user_struct *new_user; struct user_struct *root_user;
struct cred *new;
int n; int n;
ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL); ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL);
if (!ns) if (!ns)
return ERR_PTR(-ENOMEM); return -ENOMEM;
kref_init(&ns->kref); kref_init(&ns->kref);
for (n = 0; n < UIDHASH_SZ; ++n) for (n = 0; n < UIDHASH_SZ; ++n)
INIT_HLIST_HEAD(ns->uidhash_table + n); INIT_HLIST_HEAD(ns->uidhash_table + n);
/* Insert new root user. */ /* Alloc new root user. */
ns->root_user = alloc_uid(ns, 0); root_user = alloc_uid(ns, 0);
if (!ns->root_user) { if (!root_user) {
kfree(ns); kfree(ns);
return ERR_PTR(-ENOMEM); return -ENOMEM;
} }
/* Reset current->user with a new one */ /* set the new root user in the credentials under preparation */
new_user = alloc_uid(ns, current_uid()); ns->creator = new->user;
if (!new_user) { new->user = root_user;
free_uid(ns->root_user); new->uid = new->euid = new->suid = new->fsuid = 0;
kfree(ns); new->gid = new->egid = new->sgid = new->fsgid = 0;
return ERR_PTR(-ENOMEM); put_group_info(new->group_info);
} new->group_info = get_group_info(&init_groups);
#ifdef CONFIG_KEYS
/* Install the new user */ key_put(new->request_key_auth);
new = prepare_creds(); new->request_key_auth = NULL;
if (!new) { #endif
free_uid(new_user); /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
free_uid(ns->root_user);
kfree(ns);
}
free_uid(new->user);
new->user = new_user;
commit_creds(new);
return ns;
}
struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns)
{
struct user_namespace *new_ns;
BUG_ON(!old_ns);
get_user_ns(old_ns);
if (!(flags & CLONE_NEWUSER))
return old_ns;
new_ns = clone_user_ns(old_ns); /* alloc_uid() incremented the userns refcount. Just set it to 1 */
kref_set(&ns->kref, 1);
put_user_ns(old_ns); return 0;
return new_ns;
} }
void free_user_ns(struct kref *kref) void free_user_ns(struct kref *kref)
...@@ -80,7 +65,7 @@ void free_user_ns(struct kref *kref) ...@@ -80,7 +65,7 @@ void free_user_ns(struct kref *kref)
struct user_namespace *ns; struct user_namespace *ns;
ns = container_of(kref, struct user_namespace, kref); ns = container_of(kref, struct user_namespace, kref);
release_uids(ns); free_uid(ns->creator);
kfree(ns); kfree(ns);
} }
EXPORT_SYMBOL(free_user_ns); EXPORT_SYMBOL(free_user_ns);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册