diff options
author | Elena Reshetova <elena.reshetova@intel.com> | 2017-03-31 08:20:48 -0400 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2017-04-02 20:49:05 -0400 |
commit | fff292914d3a2f1efd05ca71c2ba72a3c663201e (patch) | |
tree | 627f9870ad82da8f6f06cca86a73e3b7e2fc97d5 | |
parent | 8291798dcf059cdc5e55a59b2c4ad70ae14508c2 (diff) |
security, keys: convert key.usage from atomic_t to refcount_t
refcount_t type and corresponding API should be
used instead of atomic_t when the variable is used as
a reference counter. This allows to avoid accidental
refcounter overflows that might lead to use-after-free
situations.
Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <james.l.morris@oracle.com>
-rw-r--r-- | include/linux/key.h | 5 | ||||
-rw-r--r-- | security/keys/gc.c | 2 | ||||
-rw-r--r-- | security/keys/key.c | 6 | ||||
-rw-r--r-- | security/keys/keyring.c | 8 | ||||
-rw-r--r-- | security/keys/proc.c | 2 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 2 |
6 files changed, 13 insertions, 12 deletions
diff --git a/include/linux/key.h b/include/linux/key.h index e45212f2777e..9d9fac583dd3 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/rwsem.h> | 23 | #include <linux/rwsem.h> |
24 | #include <linux/atomic.h> | 24 | #include <linux/atomic.h> |
25 | #include <linux/assoc_array.h> | 25 | #include <linux/assoc_array.h> |
26 | #include <linux/refcount.h> | ||
26 | 27 | ||
27 | #ifdef __KERNEL__ | 28 | #ifdef __KERNEL__ |
28 | #include <linux/uidgid.h> | 29 | #include <linux/uidgid.h> |
@@ -135,7 +136,7 @@ static inline bool is_key_possessed(const key_ref_t key_ref) | |||
135 | * - Kerberos TGTs and tickets | 136 | * - Kerberos TGTs and tickets |
136 | */ | 137 | */ |
137 | struct key { | 138 | struct key { |
138 | atomic_t usage; /* number of references */ | 139 | refcount_t usage; /* number of references */ |
139 | key_serial_t serial; /* key serial number */ | 140 | key_serial_t serial; /* key serial number */ |
140 | union { | 141 | union { |
141 | struct list_head graveyard_link; | 142 | struct list_head graveyard_link; |
@@ -242,7 +243,7 @@ extern void key_put(struct key *key); | |||
242 | 243 | ||
243 | static inline struct key *__key_get(struct key *key) | 244 | static inline struct key *__key_get(struct key *key) |
244 | { | 245 | { |
245 | atomic_inc(&key->usage); | 246 | refcount_inc(&key->usage); |
246 | return key; | 247 | return key; |
247 | } | 248 | } |
248 | 249 | ||
diff --git a/security/keys/gc.c b/security/keys/gc.c index addf060399e0..44789256c88c 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
@@ -220,7 +220,7 @@ continue_scanning: | |||
220 | key = rb_entry(cursor, struct key, serial_node); | 220 | key = rb_entry(cursor, struct key, serial_node); |
221 | cursor = rb_next(cursor); | 221 | cursor = rb_next(cursor); |
222 | 222 | ||
223 | if (atomic_read(&key->usage) == 0) | 223 | if (refcount_read(&key->usage) == 0) |
224 | goto found_unreferenced_key; | 224 | goto found_unreferenced_key; |
225 | 225 | ||
226 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) { | 226 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) { |
diff --git a/security/keys/key.c b/security/keys/key.c index 346fbf201c22..ff9244392d35 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -285,7 +285,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
285 | if (!key->index_key.description) | 285 | if (!key->index_key.description) |
286 | goto no_memory_3; | 286 | goto no_memory_3; |
287 | 287 | ||
288 | atomic_set(&key->usage, 1); | 288 | refcount_set(&key->usage, 1); |
289 | init_rwsem(&key->sem); | 289 | init_rwsem(&key->sem); |
290 | lockdep_set_class(&key->sem, &type->lock_class); | 290 | lockdep_set_class(&key->sem, &type->lock_class); |
291 | key->index_key.type = type; | 291 | key->index_key.type = type; |
@@ -621,7 +621,7 @@ void key_put(struct key *key) | |||
621 | if (key) { | 621 | if (key) { |
622 | key_check(key); | 622 | key_check(key); |
623 | 623 | ||
624 | if (atomic_dec_and_test(&key->usage)) | 624 | if (refcount_dec_and_test(&key->usage)) |
625 | schedule_work(&key_gc_work); | 625 | schedule_work(&key_gc_work); |
626 | } | 626 | } |
627 | } | 627 | } |
@@ -656,7 +656,7 @@ not_found: | |||
656 | 656 | ||
657 | found: | 657 | found: |
658 | /* pretend it doesn't exist if it is awaiting deletion */ | 658 | /* pretend it doesn't exist if it is awaiting deletion */ |
659 | if (atomic_read(&key->usage) == 0) | 659 | if (refcount_read(&key->usage) == 0) |
660 | goto not_found; | 660 | goto not_found; |
661 | 661 | ||
662 | /* this races with key_put(), but that doesn't matter since key_put() | 662 | /* this races with key_put(), but that doesn't matter since key_put() |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index c91e4e0cea08..3d95f7d02ba1 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -1033,7 +1033,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
1033 | /* we've got a match but we might end up racing with | 1033 | /* we've got a match but we might end up racing with |
1034 | * key_cleanup() if the keyring is currently 'dead' | 1034 | * key_cleanup() if the keyring is currently 'dead' |
1035 | * (ie. it has a zero usage count) */ | 1035 | * (ie. it has a zero usage count) */ |
1036 | if (!atomic_inc_not_zero(&keyring->usage)) | 1036 | if (!refcount_inc_not_zero(&keyring->usage)) |
1037 | continue; | 1037 | continue; |
1038 | keyring->last_used_at = current_kernel_time().tv_sec; | 1038 | keyring->last_used_at = current_kernel_time().tv_sec; |
1039 | goto out; | 1039 | goto out; |
@@ -1250,14 +1250,14 @@ int key_link(struct key *keyring, struct key *key) | |||
1250 | struct assoc_array_edit *edit; | 1250 | struct assoc_array_edit *edit; |
1251 | int ret; | 1251 | int ret; |
1252 | 1252 | ||
1253 | kenter("{%d,%d}", keyring->serial, atomic_read(&keyring->usage)); | 1253 | kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage)); |
1254 | 1254 | ||
1255 | key_check(keyring); | 1255 | key_check(keyring); |
1256 | key_check(key); | 1256 | key_check(key); |
1257 | 1257 | ||
1258 | ret = __key_link_begin(keyring, &key->index_key, &edit); | 1258 | ret = __key_link_begin(keyring, &key->index_key, &edit); |
1259 | if (ret == 0) { | 1259 | if (ret == 0) { |
1260 | kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage)); | 1260 | kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage)); |
1261 | ret = __key_link_check_restriction(keyring, key); | 1261 | ret = __key_link_check_restriction(keyring, key); |
1262 | if (ret == 0) | 1262 | if (ret == 0) |
1263 | ret = __key_link_check_live_key(keyring, key); | 1263 | ret = __key_link_check_live_key(keyring, key); |
@@ -1266,7 +1266,7 @@ int key_link(struct key *keyring, struct key *key) | |||
1266 | __key_link_end(keyring, &key->index_key, edit); | 1266 | __key_link_end(keyring, &key->index_key, edit); |
1267 | } | 1267 | } |
1268 | 1268 | ||
1269 | kleave(" = %d {%d,%d}", ret, keyring->serial, atomic_read(&keyring->usage)); | 1269 | kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage)); |
1270 | return ret; | 1270 | return ret; |
1271 | } | 1271 | } |
1272 | EXPORT_SYMBOL(key_link); | 1272 | EXPORT_SYMBOL(key_link); |
diff --git a/security/keys/proc.c b/security/keys/proc.c index b9f531c9e4fa..69199f18bfb3 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -252,7 +252,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
252 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), | 252 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), |
253 | showflag(key, 'N', KEY_FLAG_NEGATIVE), | 253 | showflag(key, 'N', KEY_FLAG_NEGATIVE), |
254 | showflag(key, 'i', KEY_FLAG_INVALIDATED), | 254 | showflag(key, 'i', KEY_FLAG_INVALIDATED), |
255 | atomic_read(&key->usage), | 255 | refcount_read(&key->usage), |
256 | xbuf, | 256 | xbuf, |
257 | key->perm, | 257 | key->perm, |
258 | from_kuid_munged(seq_user_ns(m), key->uid), | 258 | from_kuid_munged(seq_user_ns(m), key->uid), |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 6bbe2f535f08..0f062156dfb2 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -213,7 +213,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, | |||
213 | if (ret < 0) | 213 | if (ret < 0) |
214 | goto error_inst; | 214 | goto error_inst; |
215 | 215 | ||
216 | kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage)); | 216 | kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage)); |
217 | return authkey; | 217 | return authkey; |
218 | 218 | ||
219 | auth_key_revoked: | 219 | auth_key_revoked: |