summaryrefslogtreecommitdiffstats
path: root/crypto/userspace/ncr.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/userspace/ncr.c')
-rw-r--r--crypto/userspace/ncr.c52
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