Collect audited crypto operations in a list, because a single _exit()
can cause several AF_ALG sockets to be closed, and each needs to be
audited.
Add the AUDIT_CRYPTO_OP field so that crypto operations are not audited
by default, but auditing can be enabled using a rule (probably
"-F crypto_op!=0").
Signed-off-by: Miloslav Trmač <mitr(a)redhat.com>
---
include/linux/audit.h | 22 +++++++++++
kernel/auditfilter.c | 2 +
kernel/auditsc.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 124 insertions(+), 0 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index f391d45..a9516da 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -122,6 +122,8 @@
#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_USERSPACE_OP 1600 /* User-space crypto operation */
+
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
@@ -219,6 +221,7 @@
#define AUDIT_PERM 106
#define AUDIT_DIR 107
#define AUDIT_FILETYPE 108
+#define AUDIT_CRYPTO_OP 109
#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
@@ -314,6 +317,13 @@ enum {
#define AUDIT_PERM_READ 4
#define AUDIT_PERM_ATTR 8
+#define AUDIT_CRYPTO_OP_TFM_NEW 1
+#define AUDIT_CRYPTO_OP_TFM_KEY_IMPORT 2
+#define AUDIT_CRYPTO_OP_TFM_DEL 3
+#define AUDIT_CRYPTO_OP_CTX_NEW 4
+#define AUDIT_CRYPTO_OP_CTX_OP 5
+#define AUDIT_CRYPTO_OP_CTX_DEL 6
+
struct audit_status {
__u32 mask; /* Bit mask for valid entries */
__u32 enabled; /* 1 = enabled, 0 = disabled */
@@ -478,6 +488,8 @@ 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 tfm, int ctx, int ctx2,
+ const char *algorithm, const char *operation);
static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{
@@ -531,6 +543,15 @@ 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 tfm, int ctx, int ctx2,
+ const char *algorithm,
+ const char *operation)
+{
+ if (unlikely(!audit_dummy_context()))
+ return __audit_log_crypto_op(op, tfm, ctx, ctx2, algorithm, operation);
+ return 0;
+}
+
extern int audit_n_rules;
extern int audit_signals;
#else
@@ -564,6 +585,7 @@ 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, tfm, ctx, ctx2, algorithm, operation) (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 ce08041..6f35eed 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -364,6 +364,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;
@@ -454,6 +455,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data
*data,
case AUDIT_DEVMINOR:
case AUDIT_EXIT:
case AUDIT_SUCCESS:
+ case AUDIT_CRYPTO_OP:
case AUDIT_ARG0:
case AUDIT_ARG1:
case AUDIT_ARG2:
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 3828ad5..3894713 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -158,6 +158,16 @@ struct audit_aux_data_capset {
struct audit_cap_data cap;
};
+struct audit_crypto_op {
+ struct list_head list;
+ int op;
+ int tfm;
+ int ctx; /* -1 means N/A */
+ int ctx2; /* -1 means N/A */
+ const char *algorithm; /* NULL means N/A */
+ const char *operation; /* NULL means N/A */
+};
+
struct audit_tree_refs {
struct audit_tree_refs *next;
struct audit_chunk *c[31];
@@ -182,6 +192,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 */
@@ -633,6 +644,19 @@ 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_op *ax;
+
+ if (!ctx)
+ break;
+ list_for_each_entry(ax, &ctx->crypto, list) {
+ result = audit_comparator(ax->op, f->op,
+ f->val);
+ if (result)
+ break;
+ }
+ break;
+ }
}
if (!result) {
@@ -828,6 +852,7 @@ static inline void audit_free_names(struct audit_context *context)
static inline void audit_free_aux(struct audit_context *context)
{
struct audit_aux_data *aux;
+ struct audit_crypto_op *crypto, *tmp;
while ((aux = context->aux)) {
context->aux = aux->next;
@@ -837,6 +862,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);
+ kfree(crypto);
+ }
}
static inline void audit_zero_context(struct audit_context *context,
@@ -854,6 +883,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;
}
@@ -1311,12 +1341,50 @@ 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_op *crypto)
+{
+ static const char *const ops[] = {
+ [AUDIT_CRYPTO_OP_TFM_NEW] = "tfm_new",
+ [AUDIT_CRYPTO_OP_TFM_KEY_IMPORT] = "tfm_key_import",
+ [AUDIT_CRYPTO_OP_TFM_DEL] = "tfm_del",
+ [AUDIT_CRYPTO_OP_CTX_NEW] = "ctx_new",
+ [AUDIT_CRYPTO_OP_CTX_OP] = "ctx_op",
+ [AUDIT_CRYPTO_OP_CTX_DEL] = "ctx_del",
+ };
+
+ struct audit_buffer *ab;
+
+ 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]);
+ else
+ audit_log_format(ab, "crypto_op=%d", crypto->op);
+ audit_log_format(ab, " tfm=%d", crypto->tfm);
+ if (crypto->ctx != -1)
+ audit_log_format(ab, " ctx=%d", crypto->ctx);
+ if (crypto->ctx2 != -1)
+ audit_log_format(ab, " ctx2=%d", crypto->ctx2);
+ if (crypto->algorithm != NULL) {
+ audit_log_format(ab, " algorithm=");
+ audit_log_string(ab, crypto->algorithm);
+ }
+ if (crypto->operation != NULL) {
+ audit_log_format(ab, " operation=");
+ audit_log_string(ab, crypto->operation);
+ }
+ 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;
const char *tty;
/* tsk == current */
@@ -1443,6 +1511,9 @@ 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);
+
if (context->target_pid &&
audit_log_pid_context(context, context->target_pid,
context->target_auid, context->target_uid,
@@ -2484,6 +2555,35 @@ void __audit_log_capset(pid_t pid,
}
/**
+ * __audit_log_crypto_op - store information about an user-space crypto op
+ * @op: AUDIT_CRYPTO_OP_*
+ * @tfm: unique transform ID
+ * @ctx: unique context ID, or -1
+ * @ctx2: secondary context ID, or -1
+ * @algorithm: algorithm (crypto API transform) name, or NULL
+ * @operation: more detailed operation description, or NULL
+ */
+int __audit_log_crypto_op(int op, int tfm, int ctx, int ctx2,
+ const char *algorithm, const char *operation)
+{
+ struct audit_crypto_op *ax;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ return -ENOMEM;
+
+ ax->op = op;
+ ax->tfm = tfm;
+ ax->ctx = ctx;
+ ax->ctx2 = ctx2;
+ ax->algorithm = algorithm;
+ ax->operation = operation;
+ list_add_tail(&ax->list, ¤t->audit_context->crypto);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__audit_log_crypto_op);
+
+/**
* audit_core_dumps - record information about processes that end abnormally
* @signr: signal value
*
--
1.7.3.2