diff options
author | Serge Hallyn <serue@us.ibm.com> | 2008-10-15 17:38:45 -0400 |
---|---|---|
committer | Serge E. Hallyn <serue@us.ibm.com> | 2008-11-24 18:57:41 -0500 |
commit | 18b6e0414e42d95183f07d8177e3ff0241abd825 (patch) | |
tree | 91ca2f2d442055e31eb7bb551bf7060f3f4c4cc7 /fs | |
parent | 9789cfe22e5d7bc10cad841a4ea96ecedb34b267 (diff) |
User namespaces: set of cleanups (v2)
The user_ns is moved from nsproxy to user_struct, so that a struct
cred by itself is sufficient to determine access (which it otherwise
would not be). Corresponding ecryptfs fixes (by David Howells) are
here as well.
Fix refcounting. The following rules now apply:
1. The task pins the user struct.
2. The user struct pins its user namespace.
3. The user namespace pins the struct user which created it.
User namespaces are cloned during copy_creds(). Unsharing a new user_ns
is no longer possible. (We could re-add that, but it'll cause code
duplication and doesn't seem useful if PAM doesn't need to clone user
namespaces).
When a user namespace is created, its first user (uid 0) gets empty
keyrings and a clean group_info.
This incorporates a previous patch by David Howells. Here
is his original patch description:
>I suggest adding the attached incremental patch. It makes the following
>changes:
>
> (1) Provides a current_user_ns() macro to wrap accesses to current's user
> namespace.
>
> (2) Fixes eCryptFS.
>
> (3) Renames create_new_userns() to create_user_ns() to be more consistent
> with the other associated functions and because the 'new' in the name is
> superfluous.
>
> (4) Moves the argument and permission checks made for CLONE_NEWUSER to the
> beginning of do_fork() so that they're done prior to making any attempts
> at allocation.
>
> (5) Calls create_user_ns() after prepare_creds(), and gives it the new creds
> to fill in rather than have it return the new root user. I don't imagine
> the new root user being used for anything other than filling in a cred
> struct.
>
> This also permits me to get rid of a get_uid() and a free_uid(), as the
> reference the creds were holding on the old user_struct can just be
> transferred to the new namespace's creator pointer.
>
> (6) Makes create_user_ns() reset the UIDs and GIDs of the creds under
> preparation rather than doing it in copy_creds().
>
>David
>Signed-off-by: David Howells <dhowells@redhat.com>
Changelog:
Oct 20: integrate dhowells comments
1. leave thread_keyring alone
2. use current_user_ns() in set_user()
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ecryptfs/messaging.c | 13 | ||||
-rw-r--r-- | fs/ecryptfs/miscdev.c | 19 |
2 files changed, 13 insertions, 19 deletions
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index e0b0a4e28b9b..6913f727624d 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c | |||
@@ -360,7 +360,7 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, | |||
360 | struct ecryptfs_msg_ctx *msg_ctx; | 360 | struct ecryptfs_msg_ctx *msg_ctx; |
361 | size_t msg_size; | 361 | size_t msg_size; |
362 | struct nsproxy *nsproxy; | 362 | struct nsproxy *nsproxy; |
363 | struct user_namespace *current_user_ns; | 363 | struct user_namespace *tsk_user_ns; |
364 | uid_t ctx_euid; | 364 | uid_t ctx_euid; |
365 | int rc; | 365 | int rc; |
366 | 366 | ||
@@ -385,9 +385,9 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, | |||
385 | mutex_unlock(&ecryptfs_daemon_hash_mux); | 385 | mutex_unlock(&ecryptfs_daemon_hash_mux); |
386 | goto wake_up; | 386 | goto wake_up; |
387 | } | 387 | } |
388 | current_user_ns = nsproxy->user_ns; | 388 | tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns; |
389 | ctx_euid = task_euid(msg_ctx->task); | 389 | ctx_euid = task_euid(msg_ctx->task); |
390 | rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, current_user_ns); | 390 | rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns); |
391 | rcu_read_unlock(); | 391 | rcu_read_unlock(); |
392 | mutex_unlock(&ecryptfs_daemon_hash_mux); | 392 | mutex_unlock(&ecryptfs_daemon_hash_mux); |
393 | if (rc) { | 393 | if (rc) { |
@@ -405,11 +405,11 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, | |||
405 | euid, ctx_euid); | 405 | euid, ctx_euid); |
406 | goto unlock; | 406 | goto unlock; |
407 | } | 407 | } |
408 | if (current_user_ns != user_ns) { | 408 | if (tsk_user_ns != user_ns) { |
409 | rc = -EBADMSG; | 409 | rc = -EBADMSG; |
410 | printk(KERN_WARNING "%s: Received message from user_ns " | 410 | printk(KERN_WARNING "%s: Received message from user_ns " |
411 | "[0x%p]; expected message from user_ns [0x%p]\n", | 411 | "[0x%p]; expected message from user_ns [0x%p]\n", |
412 | __func__, user_ns, nsproxy->user_ns); | 412 | __func__, user_ns, tsk_user_ns); |
413 | goto unlock; | 413 | goto unlock; |
414 | } | 414 | } |
415 | if (daemon->pid != pid) { | 415 | if (daemon->pid != pid) { |
@@ -468,8 +468,7 @@ ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type, | |||
468 | uid_t euid = current_euid(); | 468 | uid_t euid = current_euid(); |
469 | int rc; | 469 | int rc; |
470 | 470 | ||
471 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, | 471 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); |
472 | current->nsproxy->user_ns); | ||
473 | if (rc || !daemon) { | 472 | if (rc || !daemon) { |
474 | rc = -ENOTCONN; | 473 | rc = -ENOTCONN; |
475 | printk(KERN_ERR "%s: User [%d] does not have a daemon " | 474 | printk(KERN_ERR "%s: User [%d] does not have a daemon " |
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c index 047ac609695b..efd95a0ed1ea 100644 --- a/fs/ecryptfs/miscdev.c +++ b/fs/ecryptfs/miscdev.c | |||
@@ -47,8 +47,7 @@ ecryptfs_miscdev_poll(struct file *file, poll_table *pt) | |||
47 | 47 | ||
48 | mutex_lock(&ecryptfs_daemon_hash_mux); | 48 | mutex_lock(&ecryptfs_daemon_hash_mux); |
49 | /* TODO: Just use file->private_data? */ | 49 | /* TODO: Just use file->private_data? */ |
50 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, | 50 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); |
51 | current->nsproxy->user_ns); | ||
52 | BUG_ON(rc || !daemon); | 51 | BUG_ON(rc || !daemon); |
53 | mutex_lock(&daemon->mux); | 52 | mutex_lock(&daemon->mux); |
54 | mutex_unlock(&ecryptfs_daemon_hash_mux); | 53 | mutex_unlock(&ecryptfs_daemon_hash_mux); |
@@ -95,11 +94,9 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file) | |||
95 | "count; rc = [%d]\n", __func__, rc); | 94 | "count; rc = [%d]\n", __func__, rc); |
96 | goto out_unlock_daemon_list; | 95 | goto out_unlock_daemon_list; |
97 | } | 96 | } |
98 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, | 97 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); |
99 | current->nsproxy->user_ns); | ||
100 | if (rc || !daemon) { | 98 | if (rc || !daemon) { |
101 | rc = ecryptfs_spawn_daemon(&daemon, euid, | 99 | rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(), |
102 | current->nsproxy->user_ns, | ||
103 | task_pid(current)); | 100 | task_pid(current)); |
104 | if (rc) { | 101 | if (rc) { |
105 | printk(KERN_ERR "%s: Error attempting to spawn daemon; " | 102 | printk(KERN_ERR "%s: Error attempting to spawn daemon; " |
@@ -153,8 +150,7 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file) | |||
153 | int rc; | 150 | int rc; |
154 | 151 | ||
155 | mutex_lock(&ecryptfs_daemon_hash_mux); | 152 | mutex_lock(&ecryptfs_daemon_hash_mux); |
156 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, | 153 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); |
157 | current->nsproxy->user_ns); | ||
158 | BUG_ON(rc || !daemon); | 154 | BUG_ON(rc || !daemon); |
159 | mutex_lock(&daemon->mux); | 155 | mutex_lock(&daemon->mux); |
160 | BUG_ON(daemon->pid != task_pid(current)); | 156 | BUG_ON(daemon->pid != task_pid(current)); |
@@ -254,8 +250,7 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count, | |||
254 | 250 | ||
255 | mutex_lock(&ecryptfs_daemon_hash_mux); | 251 | mutex_lock(&ecryptfs_daemon_hash_mux); |
256 | /* TODO: Just use file->private_data? */ | 252 | /* TODO: Just use file->private_data? */ |
257 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, | 253 | rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns()); |
258 | current->nsproxy->user_ns); | ||
259 | BUG_ON(rc || !daemon); | 254 | BUG_ON(rc || !daemon); |
260 | mutex_lock(&daemon->mux); | 255 | mutex_lock(&daemon->mux); |
261 | if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { | 256 | if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) { |
@@ -295,7 +290,7 @@ check_list: | |||
295 | goto check_list; | 290 | goto check_list; |
296 | } | 291 | } |
297 | BUG_ON(euid != daemon->euid); | 292 | BUG_ON(euid != daemon->euid); |
298 | BUG_ON(current->nsproxy->user_ns != daemon->user_ns); | 293 | BUG_ON(current_user_ns() != daemon->user_ns); |
299 | BUG_ON(task_pid(current) != daemon->pid); | 294 | BUG_ON(task_pid(current) != daemon->pid); |
300 | msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue, | 295 | msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue, |
301 | struct ecryptfs_msg_ctx, daemon_out_list); | 296 | struct ecryptfs_msg_ctx, daemon_out_list); |
@@ -468,7 +463,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf, | |||
468 | goto out_free; | 463 | goto out_free; |
469 | } | 464 | } |
470 | rc = ecryptfs_miscdev_response(&data[i], packet_size, | 465 | rc = ecryptfs_miscdev_response(&data[i], packet_size, |
471 | euid, current->nsproxy->user_ns, | 466 | euid, current_user_ns(), |
472 | task_pid(current), seq); | 467 | task_pid(current), seq); |
473 | if (rc) | 468 | if (rc) |
474 | printk(KERN_WARNING "%s: Failed to deliver miscdev " | 469 | printk(KERN_WARNING "%s: Failed to deliver miscdev " |