Skip to content

Commit 0f44e4d

Browse files
committed
keys: Move the user and user-session keyrings to the user_namespace
Move the user and user-session keyrings to the user_namespace struct rather than pinning them from the user_struct struct. This prevents these keyrings from propagating across user-namespaces boundaries with regard to the KEY_SPEC_* flags, thereby making them more useful in a containerised environment. The issue is that a single user_struct may be represent UIDs in several different namespaces. The way the patch does this is by attaching a 'register keyring' in each user_namespace and then sticking the user and user-session keyrings into that. It can then be searched to retrieve them. Signed-off-by: David Howells <[email protected]> cc: Jann Horn <[email protected]>
1 parent b206f28 commit 0f44e4d

File tree

9 files changed

+196
-129
lines changed

9 files changed

+196
-129
lines changed

include/linux/sched/user.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
#include <linux/refcount.h>
88
#include <linux/ratelimit.h>
99

10-
struct key;
11-
1210
/*
1311
* Some day this will be a full-fledged user tracking system..
1412
*/
@@ -30,18 +28,6 @@ struct user_struct {
3028
unsigned long unix_inflight; /* How many files in flight in unix sockets */
3129
atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */
3230

33-
#ifdef CONFIG_KEYS
34-
/*
35-
* These pointers can only change from NULL to a non-NULL value once.
36-
* Writes are protected by key_user_keyring_mutex.
37-
* Unlocked readers should use READ_ONCE() unless they know that
38-
* install_user_keyrings() has been called successfully (which sets
39-
* these members to non-NULL values, preventing further modifications).
40-
*/
41-
struct key *uid_keyring; /* UID specific keyring */
42-
struct key *session_keyring; /* UID's default session keyring */
43-
#endif
44-
4531
/* Hash table maintenance information */
4632
struct hlist_node uidhash_node;
4733
kuid_t uid;

include/linux/user_namespace.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,19 @@ struct user_namespace {
6565
unsigned long flags;
6666

6767
#ifdef CONFIG_KEYS
68-
/* List of joinable keyrings in this namespace */
68+
/* List of joinable keyrings in this namespace. Modification access of
69+
* these pointers is controlled by keyring_sem. Once
70+
* user_keyring_register is set, it won't be changed, so it can be
71+
* accessed directly with READ_ONCE().
72+
*/
6973
struct list_head keyring_name_list;
74+
struct key *user_keyring_register;
75+
struct rw_semaphore keyring_sem;
7076
#endif
7177

7278
/* Register of per-UID persistent keyrings for this namespace */
7379
#ifdef CONFIG_PERSISTENT_KEYRINGS
7480
struct key *persistent_keyring_register;
75-
struct rw_semaphore persistent_keyring_register_sem;
7681
#endif
7782
struct work_struct work;
7883
#ifdef CONFIG_SYSCTL

kernel/user.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,7 @@ struct user_namespace init_user_ns = {
6464
.flags = USERNS_INIT_FLAGS,
6565
#ifdef CONFIG_KEYS
6666
.keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list),
67-
#endif
68-
#ifdef CONFIG_PERSISTENT_KEYRINGS
69-
.persistent_keyring_register_sem =
70-
__RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem),
67+
.keyring_sem = __RWSEM_INITIALIZER(init_user_ns.keyring_sem),
7168
#endif
7269
};
7370
EXPORT_SYMBOL_GPL(init_user_ns);
@@ -143,8 +140,6 @@ static void free_user(struct user_struct *up, unsigned long flags)
143140
{
144141
uid_hash_remove(up);
145142
spin_unlock_irqrestore(&uidhash_lock, flags);
146-
key_put(up->uid_keyring);
147-
key_put(up->session_keyring);
148143
kmem_cache_free(uid_cachep, up);
149144
}
150145

kernel/user_namespace.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,7 @@ int create_user_ns(struct cred *new)
135135

136136
#ifdef CONFIG_KEYS
137137
INIT_LIST_HEAD(&ns->keyring_name_list);
138-
#endif
139-
#ifdef CONFIG_PERSISTENT_KEYRINGS
140-
init_rwsem(&ns->persistent_keyring_register_sem);
138+
init_rwsem(&ns->keyring_sem);
141139
#endif
142140
ret = -ENOMEM;
143141
if (!setup_userns_sysctls(ns))

security/keys/internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ extern key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx)
148148

149149
extern struct key *find_keyring_by_name(const char *name, bool uid_keyring);
150150

151-
extern int install_user_keyrings(void);
151+
extern int look_up_user_keyrings(struct key **, struct key **);
152+
extern struct key *get_user_session_keyring_rcu(const struct cred *);
152153
extern int install_thread_keyring_to_cred(struct cred *);
153154
extern int install_process_keyring_to_cred(struct cred *);
154155
extern int install_session_keyring_to_cred(struct cred *, struct key *);

security/keys/keyring.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ void key_free_user_ns(struct user_namespace *ns)
6262
list_del_init(&ns->keyring_name_list);
6363
write_unlock(&keyring_name_lock);
6464

65+
key_put(ns->user_keyring_register);
6566
#ifdef CONFIG_PERSISTENT_KEYRINGS
6667
key_put(ns->persistent_keyring_register);
6768
#endif

security/keys/persistent.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid,
9191

9292
if (ns->persistent_keyring_register) {
9393
reg_ref = make_key_ref(ns->persistent_keyring_register, true);
94-
down_read(&ns->persistent_keyring_register_sem);
94+
down_read(&ns->keyring_sem);
9595
persistent_ref = find_key_to_update(reg_ref, &index_key);
96-
up_read(&ns->persistent_keyring_register_sem);
96+
up_read(&ns->keyring_sem);
9797

9898
if (persistent_ref)
9999
goto found;
@@ -102,9 +102,9 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid,
102102
/* It wasn't in the register, so we'll need to create it. We might
103103
* also need to create the register.
104104
*/
105-
down_write(&ns->persistent_keyring_register_sem);
105+
down_write(&ns->keyring_sem);
106106
persistent_ref = key_create_persistent(ns, uid, &index_key);
107-
up_write(&ns->persistent_keyring_register_sem);
107+
up_write(&ns->keyring_sem);
108108
if (!IS_ERR(persistent_ref))
109109
goto found;
110110

0 commit comments

Comments
 (0)