summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiloslav Trmač <mitr@redhat.com>2010-09-07 00:06:02 +0200
committerMiloslav Trmač <mitr@redhat.com>2010-09-07 00:06:02 +0200
commitcf4244a8063ca5a0062f3f065574b61b4faddf59 (patch)
tree4f66b07f3e56787d4d44c0ba536259e94914e434
parent361ac15b28aed748245f8fe7a8ea349f17d4fe86 (diff)
parent9cf934e1a057a8dc4f36a1ad8d2822fb116374dd (diff)
downloadkernel-crypto-cf4244a8063ca5a0062f3f065574b61b4faddf59.tar.gz
kernel-crypto-cf4244a8063ca5a0062f3f065574b61b4faddf59.tar.xz
kernel-crypto-cf4244a8063ca5a0062f3f065574b61b4faddf59.zip
Merge branch 'audit' into integration
-rw-r--r--crypto/userspace/cryptodev_main.c15
-rw-r--r--crypto/userspace/ncr-int.h6
-rw-r--r--crypto/userspace/ncr-key-wrap.c46
-rw-r--r--crypto/userspace/ncr-key.c64
-rw-r--r--crypto/userspace/ncr-pk.c64
-rw-r--r--crypto/userspace/ncr-pk.h5
-rw-r--r--crypto/userspace/ncr-sessions.c67
-rw-r--r--crypto/userspace/ncr.c52
-rw-r--r--include/linux/audit.h55
-rw-r--r--kernel/auditfilter.c2
-rw-r--r--kernel/auditsc.c234
11 files changed, 588 insertions, 22 deletions
diff --git a/crypto/userspace/cryptodev_main.c b/crypto/userspace/cryptodev_main.c
index 0cbe3c4bdc3..89cd15b6287 100644
--- a/crypto/userspace/cryptodev_main.c
+++ b/crypto/userspace/cryptodev_main.c
@@ -31,6 +31,7 @@
*
*/
+#include <linux/audit.h>
#include <linux/crypto.h>
#include <linux/mm.h>
#include <linux/highmem.h>
@@ -102,13 +103,21 @@ int __get_userbuf(uint8_t __user *addr, uint32_t len, int write,
static int
cryptodev_open(struct inode *inode, struct file *filp)
{
- void *ncr;
+ struct ncr_lists *ncr;
+ int ret;
ncr = ncr_init_lists();
if (ncr == NULL) {
return -ENOMEM;
}
+ ret = audit_log_crypto_op(AUDIT_CRYPTO_OP_CONTEXT_NEW, ncr->id, -1,
+ NULL, NULL, -1, NULL, 0, -1, NULL, 0);
+ if (ret < 0) {
+ ncr_deinit_lists(ncr);
+ return ret;
+ }
+
filp->private_data = ncr;
return 0;
}
@@ -116,9 +125,11 @@ cryptodev_open(struct inode *inode, struct file *filp)
static int
cryptodev_release(struct inode *inode, struct file *filp)
{
- void *ncr = filp->private_data;
+ struct ncr_lists *ncr = filp->private_data;
if (ncr) {
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_CONTEXT_DEL, ncr->id, -1,
+ NULL, NULL, -1, NULL, 0, -1, NULL, 0);
ncr_deinit_lists(ncr);
filp->private_data = NULL;
}
diff --git a/crypto/userspace/ncr-int.h b/crypto/userspace/ncr-int.h
index 42c500f83da..21e782d4b5a 100644
--- a/crypto/userspace/ncr-int.h
+++ b/crypto/userspace/ncr-int.h
@@ -101,6 +101,7 @@ struct key_item_st {
uid_t uid;
pid_t pid;
+ int context_id; /* Only for auditing */
ncr_key_t desc;
};
@@ -108,6 +109,8 @@ struct key_item_st {
* are here.
*/
struct ncr_lists {
+ int id; /* Used only for auditing */
+
struct mutex key_idr_mutex;
struct idr key_idr;
@@ -116,7 +119,7 @@ struct ncr_lists {
struct idr session_idr;
};
-void* ncr_init_lists(void);
+struct ncr_lists *ncr_init_lists(void);
void ncr_deinit_lists(struct ncr_lists *lst);
long ncr_ioctl(struct ncr_lists *lst, unsigned int cmd, unsigned long arg);
@@ -206,6 +209,7 @@ int key_to_storage_data( uint8_t** data, size_t * data_size, const struct key_it
const struct algo_properties_st *_ncr_algo_to_properties(ncr_algorithm_t algo);
const struct algo_properties_st *_ncr_nla_to_properties(const struct nlattr *nla);
+const char *ncr_algorithm_name(const struct algo_properties_st *algo);
int _ncr_key_get_sec_level(struct key_item_st* item);
const struct algo_properties_st *_ncr_oid_to_properties(oid_st* oid);
const oid_st* _ncr_properties_to_oid(const struct algo_properties_st * prop, int key_size);
diff --git a/crypto/userspace/ncr-key-wrap.c b/crypto/userspace/ncr-key-wrap.c
index c30fa243941..ce061312dc0 100644
--- a/crypto/userspace/ncr-key-wrap.c
+++ b/crypto/userspace/ncr-key-wrap.c
@@ -22,6 +22,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <linux/audit.h>
#include <linux/ioctl.h>
#include <linux/mm.h>
#include <linux/ncr.h>
@@ -532,6 +533,26 @@ int kek_level, wkey_level;
return 0;
}
+static const char *ncr_wrap_name(struct nlattr *tb[])
+{
+ static const char *const known_algorithms[] = {
+ NCR_WALG_AES_RFC3394, NCR_WALG_AES_RFC5649
+ };
+
+ size_t i;
+ const struct nlattr *nla;
+
+ /* Only allow known algorithms to prevent log injection. Return the
+ static string, not nla_data(), which will go away before the ioctl()
+ handler returns. */
+ nla = tb[NCR_ATTR_WRAPPING_ALGORITHM];
+ for (i = 0; i < ARRAY_SIZE(known_algorithms); i++) {
+ if (nla_strcmp(nla, known_algorithms[i]) == 0)
+ return known_algorithms[i];
+ }
+ return "unknown";
+}
+
int ncr_key_wrap(struct ncr_lists *lst, const struct ncr_key_wrap *wrap,
struct nlattr *tb[])
{
@@ -633,6 +654,14 @@ int ret;
ret = data_size;
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_WRAP, lst->id, -1, NULL,
+ ncr_wrap_name(tb), wrap->wrapping_key,
+ key != NULL ? key->key_id : NULL,
+ key != NULL ? key->key_id_size : 0,
+ wrap->source_key,
+ wkey != NULL ? wkey->key_id : NULL,
+ wkey != NULL ? wkey->key_id_size : 0);
+
if (wkey != NULL) _ncr_key_item_put(wkey);
if (key != NULL) _ncr_key_item_put(key);
kfree(data);
@@ -710,6 +739,13 @@ int ret;
}
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_UNWRAP, lst->id, -1, NULL,
+ ncr_wrap_name(tb), wrap->wrapping_key,
+ key != NULL ? key->key_id : NULL,
+ key != NULL ? key->key_id_size : 0, wrap->dest_key,
+ wkey != NULL ? wkey->key_id : NULL,
+ wkey != NULL ? wkey->key_id_size : 0);
+
if (wkey != NULL) _ncr_key_item_put(wkey);
if (key != NULL) _ncr_key_item_put(key);
if (data != NULL) kfree(data);
@@ -773,6 +809,11 @@ int ret;
ret = data_size;
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_WRAP, lst->id, -1, NULL, NULL,
+ -1, NULL, 0, wrap->key,
+ wkey != NULL ? wkey->key_id : NULL,
+ wkey != NULL ? wkey->key_id_size : 0);
+
if (wkey != NULL) _ncr_key_item_put(wkey);
if (data != NULL) kfree(data);
if (sdata != NULL) kfree(sdata);
@@ -839,6 +880,11 @@ int ret;
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_UNWRAP, lst->id, -1, NULL, NULL,
+ -1, NULL, 0, wrap->key,
+ wkey != NULL ? wkey->key_id : NULL,
+ wkey != NULL ? wkey->key_id_size : 0);
+
if (wkey != NULL) _ncr_key_item_put(wkey);
if (data != NULL) kfree(data);
if (sdata != NULL) kfree(sdata);
diff --git a/crypto/userspace/ncr-key.c b/crypto/userspace/ncr-key.c
index e293a1b14ba..e6f7f025848 100644
--- a/crypto/userspace/ncr-key.c
+++ b/crypto/userspace/ncr-key.c
@@ -22,6 +22,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <linux/audit.h>
#include <linux/ioctl.h>
#include <linux/mm.h>
#include <linux/ncr.h>
@@ -175,6 +176,7 @@ int ncr_key_init(struct ncr_lists *lst)
atomic_set(&key->writer, 0);
key->uid = current_euid();
key->pid = task_pid_nr(current);
+ key->context_id = lst->id;
mutex_lock(&lst->key_idr_mutex);
/* idr_pre_get() should preallocate enough, and, due to key_idr_mutex,
@@ -280,9 +282,12 @@ int ret;
}
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_EXPORT, lst->id, -1, NULL,
+ ncr_algorithm_name(item->algorithm), item->desc,
+ item->key_id, item->key_id_size, -1, NULL, 0);
+
kfree(tmp);
- if (item)
- _ncr_key_item_put(item);
+ _ncr_key_item_put(item);
return ret;
}
@@ -394,8 +399,11 @@ size_t tmp_size;
ret = 0;
fail:
- if (item)
- _ncr_key_item_put(item);
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_IMPORT, lst->id, -1, NULL,
+ ncr_algorithm_name(item->algorithm), item->desc,
+ item->key_id, item->key_id_size, -1, NULL, 0);
+
+ _ncr_key_item_put(item);
kfree(tmp);
return ret;
@@ -403,6 +411,14 @@ fail:
void ncr_key_clear(struct key_item_st* item)
{
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_ZEROIZE, item->context_id, -1,
+ NULL, ncr_algorithm_name(item->algorithm),
+ item->desc, item->key_id, item->key_id_size, -1,
+ NULL, 0);
+ if (item->type == NCR_KEY_TYPE_PRIVATE ||
+ item->type == NCR_KEY_TYPE_PUBLIC)
+ ncr_pk_audit_values(item);
+
/* clears any previously allocated parameters */
if (item->type == NCR_KEY_TYPE_PRIVATE ||
item->type == NCR_KEY_TYPE_PUBLIC) {
@@ -424,7 +440,7 @@ int ncr_key_generate(struct ncr_lists *lst, const struct ncr_key_generate *gen,
{
const struct nlattr *nla;
struct key_item_st* item = NULL;
-const struct algo_properties_st *algo;
+const struct algo_properties_st *algo = NULL;
int ret;
size_t size;
@@ -484,10 +500,15 @@ size_t size;
ret = 0;
fail:
- if (item) {
- if (ret < 0) item->type = NCR_KEY_TYPE_INVALID;
- _ncr_key_item_put(item);
- }
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_GEN, lst->id, -1, NULL,
+ ncr_algorithm_name(algo), item->desc, item->key_id,
+ item->key_id_size, -1, NULL, 0);
+ if (item->type == NCR_KEY_TYPE_PUBLIC
+ || item->type == NCR_KEY_TYPE_PRIVATE)
+ ncr_pk_audit_values(item);
+
+ if (ret < 0) item->type = NCR_KEY_TYPE_INVALID;
+ _ncr_key_item_put(item);
return ret;
}
@@ -653,6 +674,10 @@ int ret;
}
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_GET_INFO, lst->id, -1, NULL,
+ ncr_algorithm_name(item->algorithm), item->desc,
+ item->key_id, item->key_id_size, -1, NULL, 0);
+
_ncr_key_item_put( item);
return ret;
@@ -718,6 +743,18 @@ int ret;
ret = 0;
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_GEN, lst->id, -1, NULL,
+ ncr_algorithm_name(private != NULL
+ ? private->algorithm : NULL),
+ private != NULL ? private->desc : -1,
+ private != NULL ? private->key_id : NULL,
+ private != NULL ? private->key_id_size : 0,
+ public != NULL ? public->desc : -1,
+ public != NULL ? public->key_id : NULL,
+ public != NULL ? public->key_id_size : 0);
+ if (public != NULL && ret >= 0)
+ ncr_pk_audit_values(public);
+
if (public) {
if (ret < 0) public->type = NCR_KEY_TYPE_INVALID;
_ncr_key_item_put(public);
@@ -780,8 +817,13 @@ struct key_item_st* newkey = NULL;
}
fail:
- if (key)
- _ncr_key_item_put(key);
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_KEY_DERIVE, lst->id, -1, NULL,
+ ncr_algorithm_name(key->algorithm), key->desc,
+ key->key_id, key->key_id_size, data->input_key,
+ newkey != NULL ? newkey->key_id : NULL,
+ newkey != NULL ? newkey->key_id_size : 0);
+
+ _ncr_key_item_put(key);
if (newkey)
_ncr_key_item_put(newkey);
return ret;
diff --git a/crypto/userspace/ncr-pk.c b/crypto/userspace/ncr-pk.c
index 3dc589a6a05..c858c2aeb18 100644
--- a/crypto/userspace/ncr-pk.c
+++ b/crypto/userspace/ncr-pk.c
@@ -22,6 +22,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <linux/audit.h>
#include <linux/ioctl.h>
#include <linux/mm.h>
#include <linux/ncr.h>
@@ -338,6 +339,69 @@ fail:
return 0;
}
+#ifdef CONFIG_AUDIT
+static int
+set_crypto_value(struct audit_crypto_value *dst, char name, mp_int *src)
+{
+ int cret;
+
+ dst->name = name;
+ dst->value_size = mp_unsigned_bin_size(src);
+ dst->value = kmalloc(dst->value_size, GFP_KERNEL);
+ cret = mp_to_unsigned_bin(src, dst->value);
+ if (cret != CRYPT_OK) {
+ kfree(dst->value);
+ return _ncr_tomerr(cret);
+ }
+ return 0;
+}
+
+void ncr_pk_audit_values(struct key_item_st *key)
+{
+ struct audit_crypto_value v[4];
+ size_t i;
+
+ i = 0;
+ switch (key->algorithm->algo) {
+#define VALUE(NAME, MPI) \
+ do { \
+ if (set_crypto_value(v + i, (NAME), (MPI)) != 0) \
+ goto free_it; \
+ i++; \
+ } while (0)
+
+ case NCR_ALG_RSA:
+ VALUE('n', &key->key.pk.rsa.N);
+ VALUE('e', &key->key.pk.rsa.e);
+ break;
+
+ case NCR_ALG_DSA:
+ VALUE('p', &key->key.pk.dsa.p);
+ VALUE('q', &key->key.pk.dsa.q);
+ VALUE('g', &key->key.pk.dsa.g);
+ VALUE('y', &key->key.pk.dsa.y);
+ break;
+
+ case NCR_ALG_DH:
+ VALUE('y', &key->key.pk.dh.y);
+ break;
+
+ default:
+ return;
+#undef VALUE
+ }
+ audit_log_crypto_values(v, i);
+ return;
+
+free_it:
+ while (i != 0) {
+ i--;
+ kfree(v[i].value);
+ }
+}
+#endif
+
+
/* Encryption/Decryption
*/
diff --git a/crypto/userspace/ncr-pk.h b/crypto/userspace/ncr-pk.h
index fb9aba5b5ee..1d4b8067d36 100644
--- a/crypto/userspace/ncr-pk.h
+++ b/crypto/userspace/ncr-pk.h
@@ -25,6 +25,11 @@ int ncr_pk_generate(const struct algo_properties_st *algo, struct nlattr *tb[],
struct key_item_st* private, struct key_item_st* public);
int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * packed_size);
int ncr_pk_unpack( struct key_item_st * key, const void * packed, size_t packed_size);
+#ifdef CONFIG_AUDIT
+void ncr_pk_audit_values(struct key_item_st *key);
+#else
+#define ncr_pk_audit_values(key) ((void)0)
+#endif
/* encryption/decryption */
int ncr_pk_cipher_init(const struct algo_properties_st *algo,
diff --git a/crypto/userspace/ncr-sessions.c b/crypto/userspace/ncr-sessions.c
index d22a38423fa..b344d087b47 100644
--- a/crypto/userspace/ncr-sessions.c
+++ b/crypto/userspace/ncr-sessions.c
@@ -23,6 +23,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <linux/audit.h>
#include <linux/crypto.h>
#include <linux/mutex.h>
#include <linux/ncr.h>
@@ -453,6 +454,32 @@ const struct algo_properties_st *_ncr_nla_to_properties(const struct nlattr *nla
return NULL;
}
+static const char *ncr_op_name(ncr_crypto_op_t op)
+{
+ static const char *const names[] = {
+ [NCR_OP_ENCRYPT] = "encrypt",
+ [NCR_OP_DECRYPT] = "decrypt",
+ [NCR_OP_SIGN] = "sign",
+ [NCR_OP_VERIFY] = "verify"
+ };
+
+ const char *res;
+
+ res = NULL;
+ if (op < ARRAY_SIZE(names))
+ res = names[op];
+ if (res == NULL)
+ res = "unknown";
+ return res;
+}
+
+const char *ncr_algorithm_name(const struct algo_properties_st *algo)
+{
+ if (algo != NULL && algo->kstr != NULL)
+ return algo->kstr;
+ return "unknown";
+}
+
static int key_item_get_nla_read(struct key_item_st **st,
struct ncr_lists *lists,
const struct nlattr *nla)
@@ -754,12 +781,30 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists,
goto fail;
}
+ ret = audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_INIT, lists->id,
+ ns->desc, ncr_op_name(ns->op),
+ ncr_algorithm_name(ns->algorithm),
+ ns->key != NULL ? ns->key->desc : -1,
+ ns->key != NULL ? ns->key->key_id : NULL,
+ ns->key != NULL ? ns->key->key_id_size : 0,
+ -1, NULL, 0);
+ if (ret != 0)
+ goto fail_noaudit;
+
if (old_session != NULL)
_ncr_sessions_item_put(old_session);
return ns;
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_INIT, lists->id, ns->desc,
+ ncr_op_name(ns->op),
+ ncr_algorithm_name(ns->algorithm),
+ ns->key != NULL ? ns->key->desc : -1,
+ ns->key != NULL ? ns->key->key_id : NULL,
+ ns->key != NULL ? ns->key->key_id_size : 0, -1,
+ NULL, 0);
+fail_noaudit:
if (old_session != NULL)
_ncr_sessions_item_put(old_session);
_ncr_sessions_item_put(ns);
@@ -976,7 +1021,8 @@ static int get_userbuf2(struct session_item_st *ses, struct nlattr *tb[],
/* Called when userspace buffers are used.
The caller is responsible for locking of the session. */
-static int _ncr_session_update(struct session_item_st *sess,
+static int _ncr_session_update(struct ncr_lists *lists,
+ struct session_item_st *sess,
struct nlattr *tb[], int compat)
{
const struct nlattr *nla;
@@ -1104,6 +1150,11 @@ static int _ncr_session_update(struct session_item_st *sess,
ret = 0;
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_OP, lists->id, sess->desc,
+ ncr_op_name(sess->op),
+ ncr_algorithm_name(sess->algorithm), -1, NULL, 0,
+ -1, NULL, 0);
+
if (sess->available_pages) {
release_user_pages(sess->pages, sess->available_pages);
sess->available_pages = 0;
@@ -1120,7 +1171,7 @@ static int try_session_update(struct ncr_lists *lists,
if (tb[NCR_ATTR_UPDATE_INPUT_KEY_AS_DATA] != NULL)
return _ncr_session_update_key(lists, sess, tb);
else if (tb[NCR_ATTR_UPDATE_INPUT_DATA] != NULL)
- return _ncr_session_update(sess, tb, compat);
+ return _ncr_session_update(lists, sess, tb, compat);
else
return 0;
}
@@ -1283,6 +1334,11 @@ static int _ncr_session_final(struct ncr_lists *lists,
fail:
kfree(buffer);
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_FINAL, lists->id,
+ sess->desc, ncr_op_name(sess->op),
+ ncr_algorithm_name(sess->algorithm), -1, NULL, 0,
+ -1, NULL, 0);
+
return ret;
}
@@ -1344,6 +1400,11 @@ static int _ncr_session_update_key(struct ncr_lists *lists,
ret = 0;
fail:
+ audit_log_crypto_op(AUDIT_CRYPTO_OP_SESSION_OP, lists->id, sess->desc,
+ ncr_op_name(sess->op),
+ ncr_algorithm_name(sess->algorithm), key->desc,
+ key->key_id, key->key_id_size, -1, NULL, 0);
+
_ncr_key_item_put(key);
return ret;
@@ -1371,7 +1432,7 @@ int ncr_session_update(struct ncr_lists *lists,
goto end;
}
if (tb[NCR_ATTR_UPDATE_INPUT_DATA] != NULL)
- ret = _ncr_session_update(sess, tb, compat);
+ ret = _ncr_session_update(lists, sess, tb, compat);
else if (tb[NCR_ATTR_UPDATE_INPUT_KEY_AS_DATA] != NULL)
ret = _ncr_session_update_key(lists, sess, tb);
else
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
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 3c7a358241a..cfb33639566 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -122,6 +122,11 @@
#define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */
#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
+#define AUDIT_CRYPTO_STORAGE_KEY 1600 /* Key storage key configured */
+#define AUDIT_CRYPTO_USERSPACE_OP 1601 /* User-space crypto operation */
+#define AUDIT_CRYPTO_KEY_VALUE 1602 /* Public values of a key, immediatelly
+ follows USERSPACE_OP. */
+
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
@@ -207,6 +212,7 @@
#define AUDIT_OBJ_TYPE 21
#define AUDIT_OBJ_LEV_LOW 22
#define AUDIT_OBJ_LEV_HIGH 23
+#define AUDIT_CRYPTO_OP 24
/* These are ONLY useful when checking
* at syscall exit time (AUDIT_AT_EXIT). */
@@ -314,6 +320,20 @@ enum {
#define AUDIT_PERM_READ 4
#define AUDIT_PERM_ATTR 8
+#define AUDIT_CRYPTO_OP_CONTEXT_NEW 1
+#define AUDIT_CRYPTO_OP_CONTEXT_DEL 2
+#define AUDIT_CRYPTO_OP_SESSION_INIT 3
+#define AUDIT_CRYPTO_OP_SESSION_OP 4
+#define AUDIT_CRYPTO_OP_SESSION_FINAL 5
+#define AUDIT_CRYPTO_OP_KEY_IMPORT 6
+#define AUDIT_CRYPTO_OP_KEY_EXPORT 7
+#define AUDIT_CRYPTO_OP_KEY_WRAP 8
+#define AUDIT_CRYPTO_OP_KEY_UNWRAP 9
+#define AUDIT_CRYPTO_OP_KEY_GEN 10
+#define AUDIT_CRYPTO_OP_KEY_DERIVE 11
+#define AUDIT_CRYPTO_OP_KEY_ZEROIZE 12
+#define AUDIT_CRYPTO_OP_KEY_GET_INFO 13
+
struct audit_status {
__u32 mask; /* Bit mask for valid entries */
__u32 enabled; /* 1 = enabled, 0 = disabled */
@@ -404,6 +424,12 @@ struct audit_field {
void *lsm_rule;
};
+struct audit_crypto_value {
+ char name;
+ void *value;
+ size_t value_size;
+};
+
#define AUDITSC_INVALID 0
#define AUDITSC_SUCCESS 1
#define AUDITSC_FAILURE 2
@@ -479,6 +505,12 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
const struct cred *new,
const struct cred *old);
extern void __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old);
+extern int __audit_log_crypto_op(int op, int context, int session,
+ const char *operation, const char *algorithm,
+ int key1, void *key1_id, size_t key1_id_size,
+ int key2, void *key2_id, size_t key2_id_size);
+extern void __audit_log_crypto_values(const struct audit_crypto_value *values,
+ size_t num_values);
static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{
@@ -532,6 +564,27 @@ static inline void audit_log_capset(pid_t pid, const struct cred *new,
__audit_log_capset(pid, new, old);
}
+static inline int audit_log_crypto_op(int op, int context, int session,
+ const char *operation,
+ const char *algorithm, int key1,
+ void *key1_id, size_t key1_id_size,
+ int key2, void *key2_id,
+ size_t key2_id_size)
+{
+ if (likely(audit_dummy_context()))
+ return 0;
+ return __audit_log_crypto_op(op, context, session, operation, algorithm,
+ key1, key1_id, key1_id_size, key2, key2_id,
+ key2_id_size);
+}
+
+static inline void audit_log_crypto_values(const struct audit_crypto_value *a,
+ size_t num_values)
+{
+ if (unlikely(!audit_dummy_context()))
+ __audit_log_crypto_values(a, num_values);
+}
+
extern int audit_n_rules;
extern int audit_signals;
#else
@@ -565,6 +618,8 @@ extern int audit_signals;
#define audit_mq_getsetattr(d,s) ((void)0)
#define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; })
#define audit_log_capset(pid, ncr, ocr) ((void)0)
+#define audit_log_crypto_op(op, ctx, sess, k1, id1, size1, k2, id2, size2) (0)
+#define audit_log_crypto_values(a, values, num_values) ((void)0)
#define audit_ptrace(t) ((void)0)
#define audit_n_rules 0
#define audit_signals 0
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index a70604047f3..a25a587dc87 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -363,6 +363,7 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
case AUDIT_DEVMINOR:
case AUDIT_EXIT:
case AUDIT_SUCCESS:
+ case AUDIT_CRYPTO_OP:
/* bit ops are only useful on syscall args */
if (f->op == Audit_bitmask || f->op == Audit_bittest)
goto exit_free;
@@ -457,6 +458,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
case AUDIT_ARG1:
case AUDIT_ARG2:
case AUDIT_ARG3:
+ case AUDIT_CRYPTO_OP:
break;
case AUDIT_ARCH:
entry->rule.arch_f = f;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index fc0f928167e..30853986ab9 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -50,6 +50,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mount.h>
+#include <linux/ncr.h>
#include <linux/socket.h>
#include <linux/mqueue.h>
#include <linux/audit.h>
@@ -80,6 +81,9 @@
/* no execve audit message should be longer than this (userspace limits) */
#define MAX_EXECVE_AUDIT_LEN 7500
+/* Number of public key values that can be audited */
+#define AUDIT_MAX_CRYPTO_KEY_VALUES 4
+
/* number of audit rules */
int audit_n_rules;
@@ -157,6 +161,32 @@ struct audit_aux_data_capset {
struct audit_cap_data cap;
};
+#define AUDIT_CRYPTO_OP_KEY_VALUE -1
+struct audit_crypto_header {
+ struct list_head list;
+ int op; /* AUDIT_CRYPTO_OP_KEY_VALUE for key values */
+};
+
+struct audit_crypto_op {
+ struct audit_crypto_header hdr;
+ int context;
+ int session;
+ const char *operation;
+ const char *algorithm;
+ int key1;
+ unsigned char key1_id[MAX_KEY_ID_SIZE];
+ size_t key1_id_size;
+ int key2;
+ unsigned char key2_id[MAX_KEY_ID_SIZE];
+ size_t key2_id_size;
+};
+
+struct audit_crypto_values {
+ struct audit_crypto_header hdr;
+ size_t num_values;
+ struct audit_crypto_value values[AUDIT_MAX_CRYPTO_KEY_VALUES];
+};
+
struct audit_tree_refs {
struct audit_tree_refs *next;
struct audit_chunk *c[31];
@@ -181,6 +211,7 @@ struct audit_context {
struct audit_context *previous; /* For nested syscalls */
struct audit_aux_data *aux;
struct audit_aux_data *aux_pids;
+ struct list_head crypto;
struct sockaddr_storage *sockaddr;
size_t sockaddr_len;
/* Save things to print about task_struct */
@@ -632,6 +663,21 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_FILETYPE:
result = audit_match_filetype(ctx, f->val);
break;
+ case AUDIT_CRYPTO_OP: {
+ struct audit_crypto_header *ax;
+
+ if (!ctx)
+ break;
+ list_for_each_entry(ax, &ctx->crypto, list) {
+ if (ax->op == AUDIT_CRYPTO_OP_KEY_VALUE)
+ continue;
+ result = audit_comparator(ax->op, f->op,
+ f->val);
+ if (result)
+ break;
+ }
+ break;
+ }
}
if (!result) {
@@ -824,9 +870,23 @@ static inline void audit_free_names(struct audit_context *context)
context->pwd.mnt = NULL;
}
+static void audit_free_crypto_op(struct audit_crypto_header *crypto)
+{
+ if (crypto->op == AUDIT_CRYPTO_OP_KEY_VALUE) {
+ struct audit_crypto_values *val;
+ size_t i;
+
+ val = (struct audit_crypto_values *)crypto;
+ for (i = 0; i < val->num_values; i++)
+ kfree(val->values[i].value);
+ }
+ kfree(crypto);
+}
+
static inline void audit_free_aux(struct audit_context *context)
{
struct audit_aux_data *aux;
+ struct audit_crypto_header *crypto, *tmp;
while ((aux = context->aux)) {
context->aux = aux->next;
@@ -836,6 +896,10 @@ static inline void audit_free_aux(struct audit_context *context)
context->aux_pids = aux->next;
kfree(aux);
}
+ list_for_each_entry_safe(crypto, tmp, &context->crypto, list) {
+ list_del(&crypto->list);
+ audit_free_crypto_op(crypto);
+ }
}
static inline void audit_zero_context(struct audit_context *context,
@@ -853,6 +917,7 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state)
if (!(context = kmalloc(sizeof(*context), GFP_KERNEL)))
return NULL;
audit_zero_context(context, state);
+ INIT_LIST_HEAD(&context->crypto);
INIT_LIST_HEAD(&context->killed_trees);
return context;
}
@@ -1310,12 +1375,91 @@ static void show_special(struct audit_context *context, int *call_panic)
audit_log_end(ab);
}
+static void log_crypto_op(struct audit_context *context,
+ const struct audit_crypto_header *header)
+{
+ static const char *const ops[] = {
+ [AUDIT_CRYPTO_OP_CONTEXT_NEW] = "context_new",
+ [AUDIT_CRYPTO_OP_CONTEXT_DEL] = "context_del",
+ [AUDIT_CRYPTO_OP_SESSION_INIT] = "session_init",
+ [AUDIT_CRYPTO_OP_SESSION_OP] = "session_op",
+ [AUDIT_CRYPTO_OP_SESSION_FINAL] = "session_final",
+ [AUDIT_CRYPTO_OP_KEY_IMPORT] = "key_import",
+ [AUDIT_CRYPTO_OP_KEY_EXPORT] = "key_export",
+ [AUDIT_CRYPTO_OP_KEY_WRAP] = "key_wrap",
+ [AUDIT_CRYPTO_OP_KEY_UNWRAP] = "key_unwrap",
+ [AUDIT_CRYPTO_OP_KEY_GEN] = "key_gen",
+ [AUDIT_CRYPTO_OP_KEY_DERIVE] = "key_derive",
+ [AUDIT_CRYPTO_OP_KEY_ZEROIZE] = "key_zeroize",
+ [AUDIT_CRYPTO_OP_KEY_GET_INFO] = "key_get_info",
+ };
+
+ const struct audit_crypto_op *crypto;
+ struct audit_buffer *ab;
+
+ crypto = (struct audit_crypto_op *)header;
+ ab = audit_log_start(context, GFP_KERNEL, AUDIT_CRYPTO_USERSPACE_OP);
+ if (!ab)
+ return;
+ if (header->op < ARRAY_SIZE(ops) && ops[header->op] != NULL)
+ audit_log_format(ab, "crypto_op=%s", ops[header->op]);
+ else
+ audit_log_format(ab, "crypto_op=%d", header->op);
+ audit_log_format(ab, " ctx=%d", crypto->context);
+ if (crypto->session != -1)
+ audit_log_format(ab, " session=%d", crypto->session);
+ if (crypto->operation != NULL) {
+ audit_log_format(ab, " operation=");
+ audit_log_string(ab, crypto->operation);
+ }
+ if (crypto->algorithm != NULL) {
+ audit_log_format(ab, " algo=");
+ audit_log_string(ab, crypto->algorithm);
+ }
+ if (crypto->key1 != -1) {
+ audit_log_format(ab, " key1=%d", crypto->key1);
+ if (crypto->key1_id_size > 0) {
+ audit_log_format(ab, " key1_id=");
+ audit_log_n_untrustedstring(ab, crypto->key1_id,
+ crypto->key1_id_size);
+ }
+ }
+ if (crypto->key2 != -1) {
+ audit_log_format(ab, " key2=%d", crypto->key2);
+ if (crypto->key2_id_size > 0) {
+ audit_log_format(ab, " key2_id=");
+ audit_log_n_untrustedstring(ab, crypto->key2_id,
+ crypto->key2_id_size);
+ }
+ }
+ audit_log_end(ab);
+}
+
+static void log_crypto_values(struct audit_context *context,
+ const struct audit_crypto_header *header)
+{
+ struct audit_buffer *ab;
+ const struct audit_crypto_values *crypto;
+ const struct audit_crypto_value *v;
+
+ crypto = (struct audit_crypto_values *)header;
+ ab = audit_log_start(context, GFP_KERNEL, AUDIT_CRYPTO_KEY_VALUE);
+ if (!ab)
+ return;
+ for (v = crypto->values; v < crypto->values + crypto->num_values; v++) {
+ audit_log_format(ab, " key_value_%c=", v->name);
+ audit_log_n_hex(ab, v->value, v->value_size);
+ }
+ audit_log_end(ab);
+}
+
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{
const struct cred *cred;
int i, call_panic = 0;
struct audit_buffer *ab;
struct audit_aux_data *aux;
+ struct audit_crypto_header *crypto;
const char *tty;
/* tsk == current */
@@ -1442,6 +1586,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
call_panic = 1;
}
+ list_for_each_entry(crypto, &context->crypto, list) {
+ if (crypto->op != AUDIT_CRYPTO_OP_KEY_VALUE)
+ log_crypto_op(context, crypto);
+ else
+ log_crypto_values(context, crypto);
+ }
+
if (context->target_pid &&
audit_log_pid_context(context, context->target_pid,
context->target_auid, context->target_uid,
@@ -2486,6 +2637,89 @@ void __audit_log_capset(pid_t pid,
}
/**
+ * __audit_log_crypto_op - store information about an user-space crypto op
+ * @op: AUDIT_CRYPTO_OP_*
+ * @context: user-space context ID
+ * @session: session ID within @context, or -1
+ * @operation: more detailed operation description, or NULL
+ * @algorithm: algorithm (crypto API transform) name, or NULL
+ * @key1: ID of key 1 within @context, or -1
+ * @key1_id: user-space ID of key 1 set from user-space if @key1 != -1
+ * @key1_id_size: Size of @key1_id
+ * @key2: ID of key 2 within @context, or -1
+ * @key2_id: user-space ID of key 2 set from user-space if @key2 != -1
+ * @key2_id_size: Size of @key2_id
+ */
+int __audit_log_crypto_op(int op, int context, int session,
+ const char *operation, const char *algorithm,
+ int key1, void *key1_id, size_t key1_id_size,
+ int key2, void *key2_id, size_t key2_id_size)
+{
+ struct audit_crypto_op *ax;
+ struct audit_context *ctx = current->audit_context;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ return -ENOMEM;
+
+ ax->hdr.op = op;
+ ax->context = context;
+ ax->session = session;
+ ax->operation = operation;
+ ax->algorithm = algorithm;
+ ax->key1 = key1;
+ if (key1 != -1) {
+ ax->key1_id_size = min(key1_id_size, sizeof(ax->key1_id));
+ memcpy(ax->key1_id, key1_id, ax->key1_id_size);
+ } else
+ ax->key1_id_size = 0;
+ ax->key2 = key2;
+ if (key2 != -1) {
+ ax->key2_id_size = min(key2_id_size, sizeof(ax->key2_id));
+ memcpy(ax->key2_id, key2_id, ax->key2_id_size);
+ } else
+ ax->key2_id_size = 0;
+ list_add_tail(&ax->hdr.list, &ctx->crypto);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__audit_log_crypto_op);
+
+/**
+ * __audit_log_crypto_op - store information about values of crypto keys
+ * @values: individual byte arrays describing the key. The "value" members
+ * must be allocated using kmalloc(), this function will take care of freeing
+ * them.
+ * @num_values: number of elements in @values
+ */
+void __audit_log_crypto_values(const struct audit_crypto_value *values,
+ size_t num_values)
+{
+ struct audit_crypto_values *ax;
+ struct audit_context *ctx = current->audit_context;
+ size_t i;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ goto free_values;
+
+ ax->hdr.op = AUDIT_CRYPTO_OP_KEY_VALUE;
+ BUG_ON(num_values > ARRAY_SIZE(ax->values));
+ ax->num_values = num_values;
+ for (i = 0; i < num_values; i++) {
+ ax->values[i].name = values[i].name;
+ ax->values[i].value = values[i].value;
+ ax->values[i].value_size = values[i].value_size;
+ }
+ list_add_tail(&ax->hdr.list, &ctx->crypto);
+ return;
+
+free_values:
+ for (i = 0; i < num_values; i++)
+ kfree(values[i].value);
+}
+EXPORT_SYMBOL_GPL(__audit_log_crypto_values);
+
+/**
* audit_core_dumps - record information about processes that end abnormally
* @signr: signal value
*