diff options
Diffstat (limited to 'security/keys/key.c')
-rw-r--r-- | security/keys/key.c | 57 |
1 files changed, 30 insertions, 27 deletions
diff --git a/security/keys/key.c b/security/keys/key.c index 51f851557389..80de8c3e9cc3 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -11,15 +11,16 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/poison.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/security.h> #include <linux/workqueue.h> +#include <linux/random.h> #include <linux/err.h> #include "internal.h" static kmem_cache_t *key_jar; -static key_serial_t key_serial_next = 3; struct rb_root key_serial_tree; /* tree of keys indexed by serial */ DEFINE_SPINLOCK(key_serial_lock); @@ -169,22 +170,23 @@ static void __init __key_insert_serial(struct key *key) /*****************************************************************************/ /* * assign a key the next unique serial number - * - we work through all the serial numbers between 2 and 2^31-1 in turn and - * then wrap + * - these are assigned randomly to avoid security issues through covert + * channel problems */ static inline void key_alloc_serial(struct key *key) { struct rb_node *parent, **p; struct key *xkey; - spin_lock(&key_serial_lock); - - /* propose a likely serial number and look for a hole for it in the + /* propose a random serial number and look for a hole for it in the * serial number tree */ - key->serial = key_serial_next; - if (key->serial < 3) - key->serial = 3; - key_serial_next = key->serial + 1; + do { + get_random_bytes(&key->serial, sizeof(key->serial)); + + key->serial >>= 1; /* negative numbers are not permitted */ + } while (key->serial < 3); + + spin_lock(&key_serial_lock); parent = NULL; p = &key_serial_tree.rb_node; @@ -204,12 +206,11 @@ static inline void key_alloc_serial(struct key *key) /* we found a key with the proposed serial number - walk the tree from * that point looking for the next unused serial number */ - serial_exists: +serial_exists: for (;;) { - key->serial = key_serial_next; + key->serial++; if (key->serial < 2) key->serial = 2; - key_serial_next = key->serial + 1; if (!rb_parent(parent)) p = &key_serial_tree.rb_node; @@ -228,7 +229,7 @@ static inline void key_alloc_serial(struct key *key) } /* we've found a suitable hole - arrange for this key to occupy it */ - insert_here: +insert_here: rb_link_node(&key->serial_node, parent, p); rb_insert_color(&key->serial_node, &key_serial_tree); @@ -248,7 +249,7 @@ static inline void key_alloc_serial(struct key *key) */ struct key *key_alloc(struct key_type *type, const char *desc, uid_t uid, gid_t gid, struct task_struct *ctx, - key_perm_t perm, int not_in_quota) + key_perm_t perm, unsigned long flags) { struct key_user *user = NULL; struct key *key; @@ -269,12 +270,14 @@ struct key *key_alloc(struct key_type *type, const char *desc, /* check that the user's quota permits allocation of another key and * its description */ - if (!not_in_quota) { + if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { spin_lock(&user->lock); - if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || - user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES - ) - goto no_quota; + if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { + if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || + user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES + ) + goto no_quota; + } user->qnkeys++; user->qnbytes += quotalen; @@ -308,7 +311,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, key->payload.data = NULL; key->security = NULL; - if (!not_in_quota) + if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) key->flags |= 1 << KEY_FLAG_IN_QUOTA; memset(&key->type_data, 0, sizeof(key->type_data)); @@ -318,7 +321,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, #endif /* let the security module know about the key */ - ret = security_key_alloc(key, ctx); + ret = security_key_alloc(key, ctx, flags); if (ret < 0) goto security_error; @@ -332,7 +335,7 @@ error: security_error: kfree(key->description); kmem_cache_free(key_jar, key); - if (!not_in_quota) { + if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { spin_lock(&user->lock); user->qnkeys--; user->qnbytes -= quotalen; @@ -345,7 +348,7 @@ security_error: no_memory_3: kmem_cache_free(key_jar, key); no_memory_2: - if (!not_in_quota) { + if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { spin_lock(&user->lock); user->qnkeys--; user->qnbytes -= quotalen; @@ -761,7 +764,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, const char *description, const void *payload, size_t plen, - int not_in_quota) + unsigned long flags) { struct key_type *ktype; struct key *keyring, *key = NULL; @@ -822,7 +825,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, /* allocate a new key */ key = key_alloc(ktype, description, current->fsuid, current->fsgid, - current, perm, not_in_quota); + current, perm, flags); if (IS_ERR(key)) { key_ref = ERR_PTR(PTR_ERR(key)); goto error_3; @@ -986,7 +989,7 @@ void unregister_key_type(struct key_type *ktype) if (key->type == ktype) { if (ktype->destroy) ktype->destroy(key); - memset(&key->payload, 0xbd, sizeof(key->payload)); + memset(&key->payload, KEY_DESTROY, sizeof(key->payload)); } } |