aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElena Reshetova <elena.reshetova@intel.com>2017-03-31 08:20:48 -0400
committerJames Morris <james.l.morris@oracle.com>2017-04-02 20:49:05 -0400
commitfff292914d3a2f1efd05ca71c2ba72a3c663201e (patch)
tree627f9870ad82da8f6f06cca86a73e3b7e2fc97d5
parent8291798dcf059cdc5e55a59b2c4ad70ae14508c2 (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.h5
-rw-r--r--security/keys/gc.c2
-rw-r--r--security/keys/key.c6
-rw-r--r--security/keys/keyring.c8
-rw-r--r--security/keys/proc.c2
-rw-r--r--security/keys/request_key_auth.c2
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 */
137struct key { 138struct 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
243static inline struct key *__key_get(struct key *key) 244static 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
657found: 657found:
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}
1272EXPORT_SYMBOL(key_link); 1272EXPORT_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
219auth_key_revoked: 219auth_key_revoked: