Skip to content

Commit b206f28

Browse files
committed
keys: Namespace keyring names
Keyring names are held in a single global list that any process can pick from by means of keyctl_join_session_keyring (provided the keyring grants Search permission). This isn't very container friendly, however. Make the following changes: (1) Make default session, process and thread keyring names begin with a '.' instead of '_'. (2) Keyrings whose names begin with a '.' aren't added to the list. Such keyrings are system specials. (3) Replace the global list with per-user_namespace lists. A keyring adds its name to the list for the user_namespace that it is currently in. (4) When a user_namespace is deleted, it just removes itself from the keyring name list. The global keyring_name_lock is retained for accessing the name lists. This allows (4) to work. This can be tested by: # keyctl newring foo @s 995906392 # unshare -U $ keyctl show ... 995906392 --alswrv 65534 65534 \_ keyring: foo ... $ keyctl session foo Joined session keyring: 935622349 As can be seen, a new session keyring was created. The capability bit KEYCTL_CAPS1_NS_KEYRING_NAME is set if the kernel is employing this feature. Signed-off-by: David Howells <[email protected]> cc: Eric W. Biederman <[email protected]>
1 parent dcf49db commit b206f28

File tree

7 files changed

+60
-60
lines changed

7 files changed

+60
-60
lines changed

include/linux/key.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ extern void key_set_timeout(struct key *, unsigned);
361361

362362
extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
363363
key_perm_t perm);
364+
extern void key_free_user_ns(struct user_namespace *);
364365

365366
/*
366367
* The permissions required on a key that we're looking up.
@@ -434,6 +435,7 @@ extern void key_init(void);
434435
#define key_fsuid_changed(c) do { } while(0)
435436
#define key_fsgid_changed(c) do { } while(0)
436437
#define key_init() do { } while(0)
438+
#define key_free_user_ns(ns) do { } while(0)
437439

438440
#endif /* CONFIG_KEYS */
439441
#endif /* __KERNEL__ */

include/linux/user_namespace.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ struct user_namespace {
6464
struct ns_common ns;
6565
unsigned long flags;
6666

67+
#ifdef CONFIG_KEYS
68+
/* List of joinable keyrings in this namespace */
69+
struct list_head keyring_name_list;
70+
#endif
71+
6772
/* Register of per-UID persistent keyrings for this namespace */
6873
#ifdef CONFIG_PERSISTENT_KEYRINGS
6974
struct key *persistent_keyring_register;

include/uapi/linux/keyctl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,6 @@ struct keyctl_pkey_params {
128128
#define KEYCTL_CAPS0_INVALIDATE 0x20 /* KEYCTL_INVALIDATE supported */
129129
#define KEYCTL_CAPS0_RESTRICT_KEYRING 0x40 /* KEYCTL_RESTRICT_KEYRING supported */
130130
#define KEYCTL_CAPS0_MOVE 0x80 /* KEYCTL_MOVE supported */
131+
#define KEYCTL_CAPS1_NS_KEYRING_NAME 0x01 /* Keyring names are per-user_namespace */
131132

132133
#endif /* _LINUX_KEYCTL_H */

kernel/user.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ struct user_namespace init_user_ns = {
6262
.ns.ops = &userns_operations,
6363
#endif
6464
.flags = USERNS_INIT_FLAGS,
65+
#ifdef CONFIG_KEYS
66+
.keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list),
67+
#endif
6568
#ifdef CONFIG_PERSISTENT_KEYRINGS
6669
.persistent_keyring_register_sem =
6770
__RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem),

kernel/user_namespace.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ int create_user_ns(struct cred *new)
133133
ns->flags = parent_ns->flags;
134134
mutex_unlock(&userns_state_mutex);
135135

136+
#ifdef CONFIG_KEYS
137+
INIT_LIST_HEAD(&ns->keyring_name_list);
138+
#endif
136139
#ifdef CONFIG_PERSISTENT_KEYRINGS
137140
init_rwsem(&ns->persistent_keyring_register_sem);
138141
#endif
@@ -196,9 +199,7 @@ static void free_user_ns(struct work_struct *work)
196199
kfree(ns->projid_map.reverse);
197200
}
198201
retire_userns_sysctls(ns);
199-
#ifdef CONFIG_PERSISTENT_KEYRINGS
200-
key_put(ns->persistent_keyring_register);
201-
#endif
202+
key_free_user_ns(ns);
202203
ns_free_inum(&ns->ns);
203204
kmem_cache_free(user_ns_cachep, ns);
204205
dec_user_namespaces(ucounts);

security/keys/keyctl.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
#define KEY_MAX_DESC_SIZE 4096
3232

33-
static const unsigned char keyrings_capabilities[1] = {
33+
static const unsigned char keyrings_capabilities[2] = {
3434
[0] = (KEYCTL_CAPS0_CAPABILITIES |
3535
(IS_ENABLED(CONFIG_PERSISTENT_KEYRINGS) ? KEYCTL_CAPS0_PERSISTENT_KEYRINGS : 0) |
3636
(IS_ENABLED(CONFIG_KEY_DH_OPERATIONS) ? KEYCTL_CAPS0_DIFFIE_HELLMAN : 0) |
@@ -40,6 +40,7 @@ static const unsigned char keyrings_capabilities[1] = {
4040
KEYCTL_CAPS0_RESTRICT_KEYRING |
4141
KEYCTL_CAPS0_MOVE
4242
),
43+
[1] = (KEYCTL_CAPS1_NS_KEYRING_NAME),
4344
};
4445

4546
static int key_get_type_from_user(char *type,

security/keys/keyring.c

Lines changed: 43 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/security.h>
1717
#include <linux/seq_file.h>
1818
#include <linux/err.h>
19+
#include <linux/user_namespace.h>
1920
#include <keys/keyring-type.h>
2021
#include <keys/user-type.h>
2122
#include <linux/assoc_array_priv.h>
@@ -28,11 +29,6 @@
2829
*/
2930
#define KEYRING_SEARCH_MAX_DEPTH 6
3031

31-
/*
32-
* We keep all named keyrings in a hash to speed looking them up.
33-
*/
34-
#define KEYRING_NAME_HASH_SIZE (1 << 5)
35-
3632
/*
3733
* We mark pointers we pass to the associative array with bit 1 set if
3834
* they're keyrings and clear otherwise.
@@ -55,17 +51,20 @@ static inline void *keyring_key_to_ptr(struct key *key)
5551
return key;
5652
}
5753

58-
static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE];
5954
static DEFINE_RWLOCK(keyring_name_lock);
6055

61-
static inline unsigned keyring_hash(const char *desc)
56+
/*
57+
* Clean up the bits of user_namespace that belong to us.
58+
*/
59+
void key_free_user_ns(struct user_namespace *ns)
6260
{
63-
unsigned bucket = 0;
64-
65-
for (; *desc; desc++)
66-
bucket += (unsigned char)*desc;
61+
write_lock(&keyring_name_lock);
62+
list_del_init(&ns->keyring_name_list);
63+
write_unlock(&keyring_name_lock);
6764

68-
return bucket & (KEYRING_NAME_HASH_SIZE - 1);
65+
#ifdef CONFIG_PERSISTENT_KEYRINGS
66+
key_put(ns->persistent_keyring_register);
67+
#endif
6968
}
7069

7170
/*
@@ -104,23 +103,17 @@ static DEFINE_MUTEX(keyring_serialise_link_lock);
104103

105104
/*
106105
* Publish the name of a keyring so that it can be found by name (if it has
107-
* one).
106+
* one and it doesn't begin with a dot).
108107
*/
109108
static void keyring_publish_name(struct key *keyring)
110109
{
111-
int bucket;
112-
113-
if (keyring->description) {
114-
bucket = keyring_hash(keyring->description);
110+
struct user_namespace *ns = current_user_ns();
115111

112+
if (keyring->description &&
113+
keyring->description[0] &&
114+
keyring->description[0] != '.') {
116115
write_lock(&keyring_name_lock);
117-
118-
if (!keyring_name_hash[bucket].next)
119-
INIT_LIST_HEAD(&keyring_name_hash[bucket]);
120-
121-
list_add_tail(&keyring->name_link,
122-
&keyring_name_hash[bucket]);
123-
116+
list_add_tail(&keyring->name_link, &ns->keyring_name_list);
124117
write_unlock(&keyring_name_lock);
125118
}
126119
}
@@ -1097,50 +1090,44 @@ key_ref_t find_key_to_update(key_ref_t keyring_ref,
10971090
*/
10981091
struct key *find_keyring_by_name(const char *name, bool uid_keyring)
10991092
{
1093+
struct user_namespace *ns = current_user_ns();
11001094
struct key *keyring;
1101-
int bucket;
11021095

11031096
if (!name)
11041097
return ERR_PTR(-EINVAL);
11051098

1106-
bucket = keyring_hash(name);
1107-
11081099
read_lock(&keyring_name_lock);
11091100

1110-
if (keyring_name_hash[bucket].next) {
1111-
/* search this hash bucket for a keyring with a matching name
1112-
* that's readable and that hasn't been revoked */
1113-
list_for_each_entry(keyring,
1114-
&keyring_name_hash[bucket],
1115-
name_link
1116-
) {
1117-
if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
1118-
continue;
1119-
1120-
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
1121-
continue;
1101+
/* Search this hash bucket for a keyring with a matching name that
1102+
* grants Search permission and that hasn't been revoked
1103+
*/
1104+
list_for_each_entry(keyring, &ns->keyring_name_list, name_link) {
1105+
if (!kuid_has_mapping(ns, keyring->user->uid))
1106+
continue;
11221107

1123-
if (strcmp(keyring->description, name) != 0)
1124-
continue;
1108+
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
1109+
continue;
11251110

1126-
if (uid_keyring) {
1127-
if (!test_bit(KEY_FLAG_UID_KEYRING,
1128-
&keyring->flags))
1129-
continue;
1130-
} else {
1131-
if (key_permission(make_key_ref(keyring, 0),
1132-
KEY_NEED_SEARCH) < 0)
1133-
continue;
1134-
}
1111+
if (strcmp(keyring->description, name) != 0)
1112+
continue;
11351113

1136-
/* we've got a match but we might end up racing with
1137-
* key_cleanup() if the keyring is currently 'dead'
1138-
* (ie. it has a zero usage count) */
1139-
if (!refcount_inc_not_zero(&keyring->usage))
1114+
if (uid_keyring) {
1115+
if (!test_bit(KEY_FLAG_UID_KEYRING,
1116+
&keyring->flags))
1117+
continue;
1118+
} else {
1119+
if (key_permission(make_key_ref(keyring, 0),
1120+
KEY_NEED_SEARCH) < 0)
11401121
continue;
1141-
keyring->last_used_at = ktime_get_real_seconds();
1142-
goto out;
11431122
}
1123+
1124+
/* we've got a match but we might end up racing with
1125+
* key_cleanup() if the keyring is currently 'dead'
1126+
* (ie. it has a zero usage count) */
1127+
if (!refcount_inc_not_zero(&keyring->usage))
1128+
continue;
1129+
keyring->last_used_at = ktime_get_real_seconds();
1130+
goto out;
11441131
}
11451132

11461133
keyring = ERR_PTR(-ENOKEY);

0 commit comments

Comments
 (0)