[PATCH v33 26/29] Audit: Add record for multiple task security contexts

Casey Schaufler
2022-03-10T23:59:50Z

Create a new audit record AUDIT_MAC_TASK_CONTEXTS.
An example of the MAC_TASK_CONTEXTS (1420) record is:

type=MAC_TASK_CONTEXTS[1420]
msg=audit(1600880931.832:113)
subj_apparmor=unconfined
subj_smack=_

When an audit event includes a AUDIT_MAC_TASK_CONTEXTS record
the "subj=" field in other records in the event will be "subj=?".
An AUDIT_MAC_TASK_CONTEXTS record is supplied when the system has
multiple security modules that may make access decisions based
on a subject security context.

Functions are created to manage the skb list in the audit_buffer.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/uapi/linux/audit.h | 1 +
kernel/audit.c | 104 ++++++++++++++++++++++++++++++++-----
2 files changed, 93 insertions(+), 12 deletions(-)

diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 8eda133ca4c1..af0aaccfaf57 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -143,6 +143,7 @@
#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
#define AUDIT_MAC_CALIPSO_ADD 1418 /* NetLabel: add CALIPSO DOI entry */
#define AUDIT_MAC_CALIPSO_DEL 1419 /* NetLabel: del CALIPSO DOI entry */
+#define AUDIT_MAC_TASK_CONTEXTS 1420 /* Multiple LSM task contexts */

#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
diff --git a/kernel/audit.c b/kernel/audit.c
index 4713e66a12af..ad825af203cf 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -2147,8 +2147,65 @@ void audit_log_key(struct audit_buffer *ab, char *key)
audit_log_format(ab, "(null)");
}

+/*
+ * A brief note on aux record management.
+ *
+ * Aux records are allocated and added to the skb list of
+ * the "main" record. The ab->skb is reset to point to the
+ * aux record on its creation. When the aux record in complete
+ * ab->skb has to be reset to point to the "main" record.
+ * This allows the audit_log_ functions to be ignorant of
+ * which kind of record it is logging to. It also avoids adding
+ * special data for aux records.
+ */
+
+/**
+ * audit_buffer_aux_new - Add an aux record buffer to the skb list
+ * @ab: audit_buffer
+ * @type: message type
+ *
+ * On success ab->skb will point to the new aux record.
+ * Returns 0 on success, -ENOMEM should allocation fail.
+ */
+static int audit_buffer_aux_new(struct audit_buffer *ab, int type)
+{
+ WARN_ON(ab->skb != skb_peek(&ab->skb_list));
+
+ ab->skb = nlmsg_new(AUDIT_BUFSIZ, ab->gfp_mask);
+ if (!ab->skb)
+ goto err;
+ if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
+ goto err;
+ skb_queue_tail(&ab->skb_list, ab->skb);
+
+ audit_log_format(ab, "audit(%llu.%03lu:%u): ",
+ (unsigned long long)ab->stamp.ctime.tv_sec,
+ ab->stamp.ctime.tv_nsec/1000000,
+ ab->stamp.serial);
+
+ return 0;
+
+err:
+ kfree_skb(ab->skb);
+ ab->skb = skb_peek(&ab->skb_list);
+ return -ENOMEM;
+}
+
+/**
+ * audit_buffer_aux_end - Switch back to the "main" record from an aux record
+ * @ab: audit_buffer
+ *
+ * Restores the "main" audit record to ab->skb.
+ */
+static void audit_buffer_aux_end(struct audit_buffer *ab)
+{
+ ab->skb = skb_peek(&ab->skb_list);
+}
+
+
int audit_log_task_context(struct audit_buffer *ab)
{
+ int i;
int error;
struct lsmblob blob;
struct lsmcontext context;
@@ -2157,16 +2214,44 @@ int audit_log_task_context(struct audit_buffer *ab)
if (!lsmblob_is_set(&blob))
return 0;

- error = security_secid_to_secctx(&blob, &context, LSMBLOB_FIRST);
+ if (!lsm_multiple_contexts()) {
+ error = security_secid_to_secctx(&blob, &context,
+ LSMBLOB_FIRST);
+ if (error) {
+ if (error != -EINVAL)
+ goto error_path;
+ return 0;
+ }

- if (error) {
- if (error != -EINVAL)
+ audit_log_format(ab, " subj=%s", context.context);
+ security_release_secctx(&context);
+ } else {
+ /* Multiple LSMs provide contexts. Include an aux record. */
+ audit_log_format(ab, " subj=?");
+ error = audit_buffer_aux_new(ab, AUDIT_MAC_TASK_CONTEXTS);
+ if (error)
goto error_path;
- return 0;
+ for (i = 0; i < LSMBLOB_ENTRIES; i++) {
+ if (blob.secid[i] == 0)
+ continue;
+ error = security_secid_to_secctx(&blob, &context, i);
+ if (error) {
+ if (error != -EINVAL)
+ audit_panic("error in audit_log_task_context");
+ audit_log_format(ab, "%ssubj_%s=?",
+ i ? " " : "",
+ lsm_slot_to_name(i));
+ } else {
+ audit_log_format(ab, "%ssubj_%s=%s",
+ i ? " " : "",
+ lsm_slot_to_name(i),
+ context.context);
+ security_release_secctx(&context);
+ }
+ }
+ audit_buffer_aux_end(ab);
}

- audit_log_format(ab, " subj=%s", context.context);
- security_release_secctx(&context);
return 0;

error_path:
@@ -2382,13 +2467,8 @@ int audit_signal_info(int sig, struct task_struct *t)
}

/**
- * __audit_log_end - end one audit record
+ * __audit_log_end - send one audit record
* @skb: the buffer to send
- *
- * We can not do a netlink send inside an irq context because it blocks (last
- * arg, flags, is not set to MSG_DONTWAIT), so the audit buffer is placed on a
- * queue and a kthread is scheduled to remove them from the queue outside the
- * irq context. May be called in any context.
*/
static void __audit_log_end(struct sk_buff *skb)
{
--
2.31.1