diff options
author | Miloslav Trmač <mitr@redhat.com> | 2010-09-07 00:06:02 +0200 |
---|---|---|
committer | Miloslav Trmač <mitr@redhat.com> | 2010-09-07 00:06:02 +0200 |
commit | cf4244a8063ca5a0062f3f065574b61b4faddf59 (patch) | |
tree | 4f66b07f3e56787d4d44c0ba536259e94914e434 | |
parent | 361ac15b28aed748245f8fe7a8ea349f17d4fe86 (diff) | |
parent | 9cf934e1a057a8dc4f36a1ad8d2822fb116374dd (diff) | |
download | kernel-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.c | 15 | ||||
-rw-r--r-- | crypto/userspace/ncr-int.h | 6 | ||||
-rw-r--r-- | crypto/userspace/ncr-key-wrap.c | 46 | ||||
-rw-r--r-- | crypto/userspace/ncr-key.c | 64 | ||||
-rw-r--r-- | crypto/userspace/ncr-pk.c | 64 | ||||
-rw-r--r-- | crypto/userspace/ncr-pk.h | 5 | ||||
-rw-r--r-- | crypto/userspace/ncr-sessions.c | 67 | ||||
-rw-r--r-- | crypto/userspace/ncr.c | 52 | ||||
-rw-r--r-- | include/linux/audit.h | 55 | ||||
-rw-r--r-- | kernel/auditfilter.c | 2 | ||||
-rw-r--r-- | kernel/auditsc.c | 234 |
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 * |