diff options
-rw-r--r-- | crypto/userspace/ncr-key.c | 8 | ||||
-rw-r--r-- | crypto/userspace/ncr-pk.c | 64 | ||||
-rw-r--r-- | crypto/userspace/ncr-pk.h | 5 | ||||
-rw-r--r-- | include/linux/audit.h | 18 | ||||
-rw-r--r-- | kernel/auditsc.c | 116 |
5 files changed, 197 insertions, 14 deletions
diff --git a/crypto/userspace/ncr-key.c b/crypto/userspace/ncr-key.c index e614f687075..e6f7f025848 100644 --- a/crypto/userspace/ncr-key.c +++ b/crypto/userspace/ncr-key.c @@ -415,6 +415,9 @@ void ncr_key_clear(struct key_item_st* item) 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 || @@ -500,6 +503,9 @@ fail: 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); @@ -746,6 +752,8 @@ fail: 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; 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/include/linux/audit.h b/include/linux/audit.h index 54cb007e340..cfb33639566 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -124,6 +124,8 @@ #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 @@ -422,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 @@ -501,6 +509,8 @@ 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) { @@ -568,6 +578,13 @@ static inline int audit_log_crypto_op(int op, int context, int session, 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 @@ -602,6 +619,7 @@ extern int audit_signals; #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/auditsc.c b/kernel/auditsc.c index fcd6d2e7ab9..30853986ab9 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -81,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; @@ -158,9 +161,14 @@ struct audit_aux_data_capset { struct audit_cap_data cap; }; -struct audit_crypto_op { +#define AUDIT_CRYPTO_OP_KEY_VALUE -1 +struct audit_crypto_header { struct list_head list; - int op; + 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; @@ -173,6 +181,12 @@ struct audit_crypto_op { 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]; @@ -650,11 +664,13 @@ static int audit_filter_rules(struct task_struct *tsk, result = audit_match_filetype(ctx, f->val); break; case AUDIT_CRYPTO_OP: { - struct audit_crypto_op *ax; + 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) @@ -854,10 +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_op *crypto, *tmp; + struct audit_crypto_header *crypto, *tmp; while ((aux = context->aux)) { context->aux = aux->next; @@ -869,7 +898,7 @@ static inline void audit_free_aux(struct audit_context *context) } list_for_each_entry_safe(crypto, tmp, &context->crypto, list) { list_del(&crypto->list); - kfree(crypto); + audit_free_crypto_op(crypto); } } @@ -1347,7 +1376,7 @@ static void show_special(struct audit_context *context, int *call_panic) } static void log_crypto_op(struct audit_context *context, - struct audit_crypto_op *crypto) + const struct audit_crypto_header *header) { static const char *const ops[] = { [AUDIT_CRYPTO_OP_CONTEXT_NEW] = "context_new", @@ -1365,15 +1394,17 @@ static void log_crypto_op(struct audit_context *context, [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 (crypto->op < ARRAY_SIZE(ops) && ops[crypto->op] != NULL) - audit_log_format(ab, "crypto_op=%s", ops[crypto->op]); + 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", crypto->op); + 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); @@ -1404,13 +1435,31 @@ static void log_crypto_op(struct audit_context *context, 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_op *crypto; + struct audit_crypto_header *crypto; const char *tty; /* tsk == current */ @@ -1537,8 +1586,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts call_panic = 1; } - list_for_each_entry(crypto, &context->crypto, list) - log_crypto_op(context, crypto); + 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, @@ -2609,7 +2662,7 @@ int __audit_log_crypto_op(int op, int context, int session, if (!ax) return -ENOMEM; - ax->op = op; + ax->hdr.op = op; ax->context = context; ax->session = session; ax->operation = operation; @@ -2626,12 +2679,47 @@ int __audit_log_crypto_op(int op, int context, int session, memcpy(ax->key2_id, key2_id, ax->key2_id_size); } else ax->key2_id_size = 0; - list_add_tail(&ax->list, &ctx->crypto); + 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 * |