diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/auditfilter.c | 2 | ||||
-rw-r--r-- | kernel/auditsc.c | 234 |
2 files changed, 236 insertions, 0 deletions
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 * |