aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2017-09-18 14:37:03 -0400
committerDavid Howells <dhowells@redhat.com>2017-09-25 10:19:57 -0400
commit237bbd29f7a049d310d907f4b2716a7feef9abf3 (patch)
treebc95e55675ae062350f77c9f6d8f8d0816b83207 /security/keys
parente645016abc803dafc75e4b8f6e4118f088900ffb (diff)
KEYS: prevent creating a different user's keyrings
It was possible for an unprivileged user to create the user and user session keyrings for another user. For example: sudo -u '#3000' sh -c 'keyctl add keyring _uid.4000 "" @u keyctl add keyring _uid_ses.4000 "" @u sleep 15' & sleep 1 sudo -u '#4000' keyctl describe @u sudo -u '#4000' keyctl describe @us This is problematic because these "fake" keyrings won't have the right permissions. In particular, the user who created them first will own them and will have full access to them via the possessor permissions, which can be used to compromise the security of a user's keys: -4: alswrv-----v------------ 3000 0 keyring: _uid.4000 -5: alswrv-----v------------ 3000 0 keyring: _uid_ses.4000 Fix it by marking user and user session keyrings with a flag KEY_FLAG_UID_KEYRING. Then, when searching for a user or user session keyring by name, skip all keyrings that don't have the flag set. Fixes: 69664cf16af4 ("keys: don't generate user and user session keyrings unless they're accessed") Cc: <stable@vger.kernel.org> [v2.6.26+] Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/internal.h2
-rw-r--r--security/keys/key.c2
-rw-r--r--security/keys/keyring.c23
-rw-r--r--security/keys/process_keys.c6
4 files changed, 21 insertions, 12 deletions
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 1c02c6547038..503adbae7b0d 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -141,7 +141,7 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
141extern key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx); 141extern key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx);
142extern key_ref_t search_process_keyrings(struct keyring_search_context *ctx); 142extern key_ref_t search_process_keyrings(struct keyring_search_context *ctx);
143 143
144extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); 144extern struct key *find_keyring_by_name(const char *name, bool uid_keyring);
145 145
146extern int install_user_keyrings(void); 146extern int install_user_keyrings(void);
147extern int install_thread_keyring_to_cred(struct cred *); 147extern int install_thread_keyring_to_cred(struct cred *);
diff --git a/security/keys/key.c b/security/keys/key.c
index 83da68d98b40..e5c0896c3a8f 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -302,6 +302,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
302 key->flags |= 1 << KEY_FLAG_IN_QUOTA; 302 key->flags |= 1 << KEY_FLAG_IN_QUOTA;
303 if (flags & KEY_ALLOC_BUILT_IN) 303 if (flags & KEY_ALLOC_BUILT_IN)
304 key->flags |= 1 << KEY_FLAG_BUILTIN; 304 key->flags |= 1 << KEY_FLAG_BUILTIN;
305 if (flags & KEY_ALLOC_UID_KEYRING)
306 key->flags |= 1 << KEY_FLAG_UID_KEYRING;
305 307
306#ifdef KEY_DEBUGGING 308#ifdef KEY_DEBUGGING
307 key->magic = KEY_DEBUG_MAGIC; 309 key->magic = KEY_DEBUG_MAGIC;
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 94f038967c17..4fa82a8a9c0e 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1097,15 +1097,15 @@ found:
1097/* 1097/*
1098 * Find a keyring with the specified name. 1098 * Find a keyring with the specified name.
1099 * 1099 *
1100 * All named keyrings in the current user namespace are searched, provided they 1100 * Only keyrings that have nonzero refcount, are not revoked, and are owned by a
1101 * grant Search permission directly to the caller (unless this check is 1101 * user in the current user namespace are considered. If @uid_keyring is %true,
1102 * skipped). Keyrings whose usage points have reached zero or who have been 1102 * the keyring additionally must have been allocated as a user or user session
1103 * revoked are skipped. 1103 * keyring; otherwise, it must grant Search permission directly to the caller.
1104 * 1104 *
1105 * Returns a pointer to the keyring with the keyring's refcount having being 1105 * Returns a pointer to the keyring with the keyring's refcount having being
1106 * incremented on success. -ENOKEY is returned if a key could not be found. 1106 * incremented on success. -ENOKEY is returned if a key could not be found.
1107 */ 1107 */
1108struct key *find_keyring_by_name(const char *name, bool skip_perm_check) 1108struct key *find_keyring_by_name(const char *name, bool uid_keyring)
1109{ 1109{
1110 struct key *keyring; 1110 struct key *keyring;
1111 int bucket; 1111 int bucket;
@@ -1133,10 +1133,15 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
1133 if (strcmp(keyring->description, name) != 0) 1133 if (strcmp(keyring->description, name) != 0)
1134 continue; 1134 continue;
1135 1135
1136 if (!skip_perm_check && 1136 if (uid_keyring) {
1137 key_permission(make_key_ref(keyring, 0), 1137 if (!test_bit(KEY_FLAG_UID_KEYRING,
1138 KEY_NEED_SEARCH) < 0) 1138 &keyring->flags))
1139 continue; 1139 continue;
1140 } else {
1141 if (key_permission(make_key_ref(keyring, 0),
1142 KEY_NEED_SEARCH) < 0)
1143 continue;
1144 }
1140 1145
1141 /* we've got a match but we might end up racing with 1146 /* we've got a match but we might end up racing with
1142 * key_cleanup() if the keyring is currently 'dead' 1147 * key_cleanup() if the keyring is currently 'dead'
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 86bced9fdbdf..293d3598153b 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -77,7 +77,8 @@ int install_user_keyrings(void)
77 if (IS_ERR(uid_keyring)) { 77 if (IS_ERR(uid_keyring)) {
78 uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, 78 uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
79 cred, user_keyring_perm, 79 cred, user_keyring_perm,
80 KEY_ALLOC_IN_QUOTA, 80 KEY_ALLOC_UID_KEYRING |
81 KEY_ALLOC_IN_QUOTA,
81 NULL, NULL); 82 NULL, NULL);
82 if (IS_ERR(uid_keyring)) { 83 if (IS_ERR(uid_keyring)) {
83 ret = PTR_ERR(uid_keyring); 84 ret = PTR_ERR(uid_keyring);
@@ -94,7 +95,8 @@ int install_user_keyrings(void)
94 session_keyring = 95 session_keyring =
95 keyring_alloc(buf, user->uid, INVALID_GID, 96 keyring_alloc(buf, user->uid, INVALID_GID,
96 cred, user_keyring_perm, 97 cred, user_keyring_perm,
97 KEY_ALLOC_IN_QUOTA, 98 KEY_ALLOC_UID_KEYRING |
99 KEY_ALLOC_IN_QUOTA,
98 NULL, NULL); 100 NULL, NULL);
99 if (IS_ERR(session_keyring)) { 101 if (IS_ERR(session_keyring)) {
100 ret = PTR_ERR(session_keyring); 102 ret = PTR_ERR(session_keyring);