diff options
Diffstat (limited to 'crypto/userspace/ncr.c')
-rw-r--r-- | crypto/userspace/ncr.c | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/crypto/userspace/ncr.c b/crypto/userspace/ncr.c index e643fe139a0..01ad1703c58 100644 --- a/crypto/userspace/ncr.c +++ b/crypto/userspace/ncr.c @@ -22,10 +22,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include <linux/audit.h> #include <linux/compat.h> #include <linux/crypto.h> #include <linux/ioctl.h> #include <linux/mm.h> +#include <linux/mutex.h> #include <linux/highmem.h> #include <linux/random.h> #include <linux/uaccess.h> @@ -42,7 +44,10 @@ */ struct key_item_st master_key; -void* ncr_init_lists(void) +static struct mutex lists_ida_mutex; +static DEFINE_IDA(lists_ida); + +struct ncr_lists *ncr_init_lists(void) { struct ncr_lists *lst; @@ -54,6 +59,19 @@ void* ncr_init_lists(void) memset(lst, 0, sizeof(*lst)); + mutex_init(&lists_ida_mutex); + mutex_lock(&lists_ida_mutex); + /* ida_pre_get() should preallocate enough, and, due to lists_ida_mutex, + nobody else can use the preallocated data. Therefore the loop + recommended in idr_get_new() documentation is not necessary. */ + if (ida_pre_get(&lists_ida, GFP_KERNEL) == 0 || + ida_get_new(&lists_ida, &lst->id) != 0) { + mutex_unlock(&lists_ida_mutex); + kfree(lst); + return NULL; + } + mutex_unlock(&lists_ida_mutex); + mutex_init(&lst->key_idr_mutex); idr_init(&lst->key_idr); @@ -68,6 +86,11 @@ void ncr_deinit_lists(struct ncr_lists *lst) if(lst) { ncr_key_list_deinit(lst); ncr_sessions_list_deinit(lst); + + mutex_lock(&lists_ida_mutex); + ida_remove(&lists_ida, lst->id); + mutex_unlock(&lists_ida_mutex); + kfree(lst); } } @@ -80,19 +103,30 @@ void ncr_master_key_reset(void) static int ncr_master_key_set(const struct ncr_master_key_set *st, struct nlattr *tb[]) { + struct audit_buffer *ab; + int ret; + if (!capable(CAP_SYS_ADMIN)) { err(); return -EPERM; } + /* This will also cause auditing of the syscall, including information + about the process, and success/failure indication. Note that on + error the AUDIT_CRYPTO_STORAGE_KEY record will be empty. */ + ab = audit_log_start(current->audit_context, GFP_KERNEL, + AUDIT_CRYPTO_STORAGE_KEY); + if (st->key_size > sizeof(master_key.key.secret.data)) { err(); - return -EINVAL; + ret = -EINVAL; + goto end; } if (st->key_size != 16 && st->key_size != 24 && st->key_size != 32) { dprintk(0, KERN_DEBUG, "Master key size must be 16,24 or 32.\n"); - return -EINVAL; + ret = -EINVAL; + goto end; } if (master_key.type != NCR_KEY_TYPE_INVALID) { @@ -102,15 +136,23 @@ static int ncr_master_key_set(const struct ncr_master_key_set *st, if (unlikely(copy_from_user(master_key.key.secret.data, st->key, st->key_size))) { err(); - return -EFAULT; + ret = -EFAULT; + goto end; } dprintk(0, KERN_INFO, "Initializing master key.\n"); + /* Not much we can reveal... */ + audit_log_format(ab, "key_size=%u", (unsigned)st->key_size); master_key.type = NCR_KEY_TYPE_SECRET; master_key.key.secret.size = st->key_size; - return 0; + ret = 0; + +end: + audit_log_end(ab); + + return ret; } long |