* [PATCH v4 0/4] Audit: Records for multiple security contexts
[not found] <20250607005134.10488-1-casey.ref@schaufler-ca.com>
@ 2025-06-07 0:51 ` Casey Schaufler
2025-06-07 0:51 ` [PATCH v4 1/4] Audit: Create audit_stamp structure Casey Schaufler
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Casey Schaufler @ 2025-06-07 0:51 UTC (permalink / raw)
To: casey, paul, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux
The Linux audit system includes LSM based security "context" information
in its events. Historically, only one LSM that uses security contexts can
be active on a system. One of the few obsticles to allowing multiple LSM
support is the inability to report more than one security context in an
audit event. This patchset provides a mechanism to provide supplimental
records containing more than one security context for subjects and
objects.
The mechanism for reporting multiple security contexts inspired
considerable discussion. It would have been possible to add multiple
contexts to existing records using sophisticated formatting. This would
have significant backward compatibility issues, and require additional
parsing in user space code. Adding new records for an event that contain
the contexts is more in keeping with the way audit events have been
constructed in the past.
Only audit events associated with system calls have required multiple
records prior to this. Mechanism has been added allowing any event
to be composed of multiple records. This should make it easier to
add information to existing audit events without breaking backward
compatability.
v4:
Use LSM_ID_UNDEF when checking for valid LSM IDs in
security_lsmprop_to_secctx().
Fix the object record to include only those for LSMs that use them.
Squash the two patches dealing with subject contexts.
Base the patches on Paul Moore's LSM initialization patchset.
https://lore.kernel.org/all/20250409185019.238841-31-paul@paul-moore.com/
v3:
Rework how security modules identify that they provide security
contexts to the audit system. Maintain a list within the audit
system of the security modules that provide security contexts.
Revert the separate counts of subject and object contexts.
v2:
Maintain separate counts for LSMs using subject contexts and object
contexts. AppArmor uses the former but not the latter.
Correct error handling in object record creation.
https://github.com/cschaufler/lsm-stacking#audit-6.14-rc1-v4
Casey Schaufler (4):
Audit: Create audit_stamp structure
LSM: security_lsmblob_to_secctx module selection
Audit: Add record for multiple task security contexts
Audit: Add record for multiple object contexts
include/linux/audit.h | 23 +++
include/linux/security.h | 6 +-
include/uapi/linux/audit.h | 2 +
kernel/audit.c | 274 ++++++++++++++++++++++++++++++-----
kernel/audit.h | 13 +-
kernel/auditsc.c | 65 +++------
net/netlabel/netlabel_user.c | 8 +-
security/apparmor/lsm.c | 3 +
security/lsm.h | 4 -
security/lsm_init.c | 5 -
security/security.c | 16 +-
security/selinux/hooks.c | 4 +
security/smack/smack_lsm.c | 4 +
13 files changed, 318 insertions(+), 109 deletions(-)
--
2.47.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 1/4] Audit: Create audit_stamp structure
2025-06-07 0:51 ` [PATCH v4 0/4] Audit: Records for multiple security contexts Casey Schaufler
@ 2025-06-07 0:51 ` Casey Schaufler
2025-06-07 0:51 ` [PATCH v4 2/4] LSM: security_lsmblob_to_secctx module selection Casey Schaufler
` (2 subsequent siblings)
3 siblings, 0 replies; 10+ messages in thread
From: Casey Schaufler @ 2025-06-07 0:51 UTC (permalink / raw)
To: casey, paul, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux
Replace the timestamp and serial number pair used in audit records
with a structure containing the two elements.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
kernel/audit.c | 17 +++++++++--------
kernel/audit.h | 13 +++++++++----
kernel/auditsc.c | 22 +++++++++-------------
3 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/kernel/audit.c b/kernel/audit.c
index 5f5bf85bcc90..2a567f667528 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1833,11 +1833,11 @@ unsigned int audit_serial(void)
}
static inline void audit_get_stamp(struct audit_context *ctx,
- struct timespec64 *t, unsigned int *serial)
+ struct audit_stamp *stamp)
{
- if (!ctx || !auditsc_get_stamp(ctx, t, serial)) {
- ktime_get_coarse_real_ts64(t);
- *serial = audit_serial();
+ if (!ctx || !auditsc_get_stamp(ctx, stamp)) {
+ ktime_get_coarse_real_ts64(&stamp->ctime);
+ stamp->serial = audit_serial();
}
}
@@ -1860,8 +1860,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
int type)
{
struct audit_buffer *ab;
- struct timespec64 t;
- unsigned int serial;
+ struct audit_stamp stamp;
if (audit_initialized != AUDIT_INITIALIZED)
return NULL;
@@ -1916,12 +1915,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
return NULL;
}
- audit_get_stamp(ab->ctx, &t, &serial);
+ audit_get_stamp(ab->ctx, &stamp);
/* cancel dummy context to enable supporting records */
if (ctx)
ctx->dummy = 0;
audit_log_format(ab, "audit(%llu.%03lu:%u): ",
- (unsigned long long)t.tv_sec, t.tv_nsec/1000000, serial);
+ (unsigned long long)stamp.ctime.tv_sec,
+ stamp.ctime.tv_nsec/1000000,
+ stamp.serial);
return ab;
}
diff --git a/kernel/audit.h b/kernel/audit.h
index 0211cb307d30..4d6dd2588f9b 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -99,6 +99,12 @@ struct audit_proctitle {
char *value; /* the cmdline field */
};
+/* A timestamp/serial pair to identify an event */
+struct audit_stamp {
+ struct timespec64 ctime; /* time of syscall entry */
+ unsigned int serial; /* serial number for record */
+};
+
/* The per-task audit context. */
struct audit_context {
int dummy; /* must be the first element */
@@ -108,10 +114,9 @@ struct audit_context {
AUDIT_CTX_URING, /* in use by io_uring */
} context;
enum audit_state state, current_state;
- unsigned int serial; /* serial number for record */
+ struct audit_stamp stamp; /* event identifier */
int major; /* syscall number */
int uring_op; /* uring operation */
- struct timespec64 ctime; /* time of syscall entry */
unsigned long argv[4]; /* syscall arguments */
long return_code;/* syscall return code */
u64 prio;
@@ -263,7 +268,7 @@ extern void audit_put_tty(struct tty_struct *tty);
extern unsigned int audit_serial(void);
#ifdef CONFIG_AUDITSYSCALL
extern int auditsc_get_stamp(struct audit_context *ctx,
- struct timespec64 *t, unsigned int *serial);
+ struct audit_stamp *stamp);
extern void audit_put_watch(struct audit_watch *watch);
extern void audit_get_watch(struct audit_watch *watch);
@@ -304,7 +309,7 @@ extern void audit_filter_inodes(struct task_struct *tsk,
struct audit_context *ctx);
extern struct list_head *audit_killed_trees(void);
#else /* CONFIG_AUDITSYSCALL */
-#define auditsc_get_stamp(c, t, s) 0
+#define auditsc_get_stamp(c, s) 0
#define audit_put_watch(w) do { } while (0)
#define audit_get_watch(w) do { } while (0)
#define audit_to_watch(k, p, l, o) (-EINVAL)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 78fd876a5473..528b6d2f5cb0 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -994,10 +994,10 @@ static void audit_reset_context(struct audit_context *ctx)
*/
ctx->current_state = ctx->state;
- ctx->serial = 0;
+ ctx->stamp.serial = 0;
+ ctx->stamp.ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 };
ctx->major = 0;
ctx->uring_op = 0;
- ctx->ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 };
memset(ctx->argv, 0, sizeof(ctx->argv));
ctx->return_code = 0;
ctx->prio = (ctx->state == AUDIT_STATE_RECORD ? ~0ULL : 0);
@@ -1917,7 +1917,7 @@ void __audit_uring_entry(u8 op)
ctx->context = AUDIT_CTX_URING;
ctx->current_state = ctx->state;
- ktime_get_coarse_real_ts64(&ctx->ctime);
+ ktime_get_coarse_real_ts64(&ctx->stamp.ctime);
}
/**
@@ -2039,7 +2039,7 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
context->argv[3] = a4;
context->context = AUDIT_CTX_SYSCALL;
context->current_state = state;
- ktime_get_coarse_real_ts64(&context->ctime);
+ ktime_get_coarse_real_ts64(&context->stamp.ctime);
}
/**
@@ -2508,21 +2508,17 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
/**
* auditsc_get_stamp - get local copies of audit_context values
* @ctx: audit_context for the task
- * @t: timespec64 to store time recorded in the audit_context
- * @serial: serial value that is recorded in the audit_context
+ * @stamp: timestamp to record
*
* Also sets the context as auditable.
*/
-int auditsc_get_stamp(struct audit_context *ctx,
- struct timespec64 *t, unsigned int *serial)
+int auditsc_get_stamp(struct audit_context *ctx, struct audit_stamp *stamp)
{
if (ctx->context == AUDIT_CTX_UNUSED)
return 0;
- if (!ctx->serial)
- ctx->serial = audit_serial();
- t->tv_sec = ctx->ctime.tv_sec;
- t->tv_nsec = ctx->ctime.tv_nsec;
- *serial = ctx->serial;
+ if (!ctx->stamp.serial)
+ ctx->stamp.serial = audit_serial();
+ *stamp = ctx->stamp;
if (!ctx->prio) {
ctx->prio = 1;
ctx->current_state = AUDIT_STATE_RECORD;
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 2/4] LSM: security_lsmblob_to_secctx module selection
2025-06-07 0:51 ` [PATCH v4 0/4] Audit: Records for multiple security contexts Casey Schaufler
2025-06-07 0:51 ` [PATCH v4 1/4] Audit: Create audit_stamp structure Casey Schaufler
@ 2025-06-07 0:51 ` Casey Schaufler
2025-06-16 20:54 ` Paul Moore
2025-06-07 0:51 ` [PATCH v4 3/4] Audit: Add record for multiple task security contexts Casey Schaufler
2025-06-07 0:51 ` [PATCH v4 4/4] Audit: Add record for multiple object contexts Casey Schaufler
3 siblings, 1 reply; 10+ messages in thread
From: Casey Schaufler @ 2025-06-07 0:51 UTC (permalink / raw)
To: casey, paul, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux
Add a parameter lsmid to security_lsmblob_to_secctx() to identify which
of the security modules that may be active should provide the security
context. If the value of lsmid is LSM_ID_UNDEF the first LSM providing
a hook is used. security_secid_to_secctx() is unchanged, and will
always report the first LSM providing a hook.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/security.h | 6 ++++--
kernel/audit.c | 4 ++--
kernel/auditsc.c | 8 +++++---
net/netlabel/netlabel_user.c | 3 ++-
security/security.c | 13 +++++++++++--
5 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index a0ff4fc69375..2707b514670f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -565,7 +565,8 @@ int security_setprocattr(int lsmid, const char *name, void *value, size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, struct lsm_context *cp);
-int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp);
+int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp,
+ int lsmid);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(struct lsm_context *cp);
void security_inode_invalidate_secctx(struct inode *inode);
@@ -1542,7 +1543,8 @@ static inline int security_secid_to_secctx(u32 secid, struct lsm_context *cp)
}
static inline int security_lsmprop_to_secctx(struct lsm_prop *prop,
- struct lsm_context *cp)
+ struct lsm_context *cp,
+ int lsmid)
{
return -EOPNOTSUPP;
}
diff --git a/kernel/audit.c b/kernel/audit.c
index 2a567f667528..6bbadb605ca3 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1473,7 +1473,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
case AUDIT_SIGNAL_INFO:
if (lsmprop_is_set(&audit_sig_lsm)) {
err = security_lsmprop_to_secctx(&audit_sig_lsm,
- &lsmctx);
+ &lsmctx, LSM_ID_UNDEF);
if (err < 0)
return err;
}
@@ -2188,7 +2188,7 @@ int audit_log_task_context(struct audit_buffer *ab)
if (!lsmprop_is_set(&prop))
return 0;
- error = security_lsmprop_to_secctx(&prop, &ctx);
+ error = security_lsmprop_to_secctx(&prop, &ctx, LSM_ID_UNDEF);
if (error < 0) {
if (error != -EINVAL)
goto error_path;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 528b6d2f5cb0..322d4e27f28e 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1109,7 +1109,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
from_kuid(&init_user_ns, auid),
from_kuid(&init_user_ns, uid), sessionid);
if (lsmprop_is_set(prop)) {
- if (security_lsmprop_to_secctx(prop, &ctx) < 0) {
+ if (security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF) < 0) {
audit_log_format(ab, " obj=(none)");
rc = 1;
} else {
@@ -1395,7 +1395,8 @@ static void show_special(struct audit_context *context, int *call_panic)
struct lsm_context lsmctx;
if (security_lsmprop_to_secctx(&context->ipc.oprop,
- &lsmctx) < 0) {
+ &lsmctx,
+ LSM_ID_UNDEF) < 0) {
*call_panic = 1;
} else {
audit_log_format(ab, " obj=%s", lsmctx.context);
@@ -1560,7 +1561,8 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
if (lsmprop_is_set(&n->oprop)) {
struct lsm_context ctx;
- if (security_lsmprop_to_secctx(&n->oprop, &ctx) < 0) {
+ if (security_lsmprop_to_secctx(&n->oprop, &ctx,
+ LSM_ID_UNDEF) < 0) {
if (call_panic)
*call_panic = 2;
} else {
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 0d04d23aafe7..6d6545297ee3 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -98,7 +98,8 @@ struct audit_buffer *netlbl_audit_start_common(int type,
audit_info->sessionid);
if (lsmprop_is_set(&audit_info->prop) &&
- security_lsmprop_to_secctx(&audit_info->prop, &ctx) > 0) {
+ security_lsmprop_to_secctx(&audit_info->prop, &ctx,
+ LSM_ID_UNDEF) > 0) {
audit_log_format(audit_buf, " subj=%s", ctx.context);
security_release_secctx(&ctx);
}
diff --git a/security/security.c b/security/security.c
index 2b9dde02f4de..306860434200 100644
--- a/security/security.c
+++ b/security/security.c
@@ -3774,6 +3774,7 @@ EXPORT_SYMBOL(security_ismaclabel);
* security_secid_to_secctx() - Convert a secid to a secctx
* @secid: secid
* @cp: the LSM context
+ * @lsmid: which security module to report
*
* Convert secid to security context. If @cp is NULL the length of the
* result will be returned, but no data will be returned. This
@@ -3800,9 +3801,17 @@ EXPORT_SYMBOL(security_secid_to_secctx);
*
* Return: Return length of data on success, error on failure.
*/
-int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp)
+int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp,
+ int lsmid)
{
- return call_int_hook(lsmprop_to_secctx, prop, cp);
+ struct lsm_static_call *scall;
+
+ lsm_for_each_hook(scall, lsmprop_to_secctx) {
+ if (lsmid != LSM_ID_UNDEF && lsmid != scall->hl->lsmid->id)
+ continue;
+ return scall->hl->hook.lsmprop_to_secctx(prop, cp);
+ }
+ return LSM_RET_DEFAULT(lsmprop_to_secctx);
}
EXPORT_SYMBOL(security_lsmprop_to_secctx);
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 3/4] Audit: Add record for multiple task security contexts
2025-06-07 0:51 ` [PATCH v4 0/4] Audit: Records for multiple security contexts Casey Schaufler
2025-06-07 0:51 ` [PATCH v4 1/4] Audit: Create audit_stamp structure Casey Schaufler
2025-06-07 0:51 ` [PATCH v4 2/4] LSM: security_lsmblob_to_secctx module selection Casey Schaufler
@ 2025-06-07 0:51 ` Casey Schaufler
2025-06-16 20:54 ` Paul Moore
2025-06-07 0:51 ` [PATCH v4 4/4] Audit: Add record for multiple object contexts Casey Schaufler
3 siblings, 1 reply; 10+ messages in thread
From: Casey Schaufler @ 2025-06-07 0:51 UTC (permalink / raw)
To: casey, paul, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux
Replace the single skb pointer in an audit_buffer with a list of
skb pointers. Add the audit_stamp information to the audit_buffer as
there's no guarantee that there will be an audit_context containing
the stamp associated with the event. At audit_log_end() time create
auxiliary records as have been added to the list. Functions are
created to manage the skb list in the audit_buffer.
Create a new audit record AUDIT_MAC_TASK_CONTEXTS.
An example of the MAC_TASK_CONTEXTS record is:
type=MAC_TASK_CONTEXTS
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.
Refactor audit_log_task_context(), creating a new audit_log_subj_ctx().
This is used in netlabel auditing to provide multiple subject security
contexts as necessary.
Suggested-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/audit.h | 16 +++
include/uapi/linux/audit.h | 1 +
kernel/audit.c | 207 +++++++++++++++++++++++++++++------
net/netlabel/netlabel_user.c | 9 +-
security/apparmor/lsm.c | 3 +
security/lsm.h | 4 -
security/lsm_init.c | 5 -
security/security.c | 3 -
security/selinux/hooks.c | 3 +
security/smack/smack_lsm.c | 3 +
10 files changed, 202 insertions(+), 52 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 0050ef288ab3..5020939fb8bc 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -37,6 +37,8 @@ struct audit_watch;
struct audit_tree;
struct sk_buff;
struct kern_ipc_perm;
+struct lsm_id;
+struct lsm_prop;
struct audit_krule {
u32 pflags;
@@ -147,6 +149,9 @@ extern unsigned compat_signal_class[];
#define AUDIT_TTY_ENABLE BIT(0)
#define AUDIT_TTY_LOG_PASSWD BIT(1)
+/* bit values for audit_lsm_secctx */
+#define AUDIT_SECCTX_SUBJECT BIT(0)
+
struct filename;
#define AUDIT_OFF 0
@@ -185,6 +190,7 @@ extern void audit_log_path_denied(int type,
const char *operation);
extern void audit_log_lost(const char *message);
+extern int audit_log_subj_ctx(struct audit_buffer *ab, struct lsm_prop *prop);
extern int audit_log_task_context(struct audit_buffer *ab);
extern void audit_log_task_info(struct audit_buffer *ab);
@@ -210,6 +216,8 @@ extern u32 audit_enabled;
extern int audit_signal_info(int sig, struct task_struct *t);
+extern void audit_lsm_secctx(const struct lsm_id *lsmid, int flags);
+
#else /* CONFIG_AUDIT */
static inline __printf(4, 5)
void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type,
@@ -245,6 +253,11 @@ static inline void audit_log_key(struct audit_buffer *ab, char *key)
{ }
static inline void audit_log_path_denied(int type, const char *operation)
{ }
+static inline int audit_log_subj_ctx(struct audit_buffer *ab,
+ struct lsm_prop *prop)
+{
+ return 0;
+}
static inline int audit_log_task_context(struct audit_buffer *ab)
{
return 0;
@@ -269,6 +282,9 @@ static inline int audit_signal_info(int sig, struct task_struct *t)
return 0;
}
+static inline void audit_lsm_secctx(const struct lsm_id *lsmid, int flags)
+{ }
+
#endif /* CONFIG_AUDIT */
#ifdef CONFIG_AUDIT_COMPAT_GENERIC
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 9a4ecc9f6dc5..8cad2f307719 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -148,6 +148,7 @@
#define AUDIT_IPE_POLICY_LOAD 1422 /* IPE policy load */
#define AUDIT_LANDLOCK_ACCESS 1423 /* Landlock denial */
#define AUDIT_LANDLOCK_DOMAIN 1424 /* Landlock domain status */
+#define AUDIT_MAC_TASK_CONTEXTS 1425 /* 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 6bbadb605ca3..0987b2f391cc 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -54,6 +54,7 @@
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/security.h>
+#include <linux/lsm_hooks.h>
#include <linux/freezer.h>
#include <linux/pid_namespace.h>
#include <net/netns/generic.h>
@@ -81,6 +82,11 @@ static u32 audit_failure = AUDIT_FAIL_PRINTK;
/* private audit network namespace index */
static unsigned int audit_net_id;
+/* Number of modules that provide a security context.
+ List of lsms that provide a security context */
+static u32 audit_subj_secctx_cnt;
+static const struct lsm_id *audit_subj_lsms[MAX_LSM_COUNT];
+
/**
* struct audit_net - audit private network namespace data
* @sk: communication socket
@@ -195,8 +201,10 @@ static struct audit_ctl_mutex {
* to place it on a transmit queue. Multiple audit_buffers can be in
* use simultaneously. */
struct audit_buffer {
- struct sk_buff *skb; /* formatted skb ready to send */
+ struct sk_buff *skb; /* the skb for audit_log functions */
+ struct sk_buff_head skb_list; /* formatted skbs, ready to send */
struct audit_context *ctx; /* NULL or associated context */
+ struct audit_stamp stamp; /* audit stamp for these records */
gfp_t gfp_mask;
};
@@ -278,6 +286,27 @@ static pid_t auditd_pid_vnr(void)
return pid;
}
+/**
+ * audit_lsm_secctx - Identify a security module as providing a secctx.
+ * @lsmid: LSM identity
+ * @flags: which contexts are provided
+ *
+ * Description:
+ * Increments the count of the security modules providing a secctx.
+ * If the LSM id is already in the list leave it alone.
+ */
+void audit_lsm_secctx(const struct lsm_id *lsmid, int flags)
+{
+ int i;
+
+ if (flags & AUDIT_SECCTX_SUBJECT) {
+ for (i = 0 ; i < audit_subj_secctx_cnt; i++)
+ if (audit_subj_lsms[i] == lsmid)
+ return;
+ audit_subj_lsms[audit_subj_secctx_cnt++] = lsmid;
+ }
+}
+
/**
* audit_get_sk - Return the audit socket for the given network namespace
* @net: the destination network namespace
@@ -1776,10 +1805,13 @@ __setup("audit_backlog_limit=", audit_backlog_limit_set);
static void audit_buffer_free(struct audit_buffer *ab)
{
+ struct sk_buff *skb;
+
if (!ab)
return;
- kfree_skb(ab->skb);
+ while ((skb = skb_dequeue(&ab->skb_list)))
+ kfree_skb(skb);
kmem_cache_free(audit_buffer_cache, ab);
}
@@ -1795,6 +1827,10 @@ static struct audit_buffer *audit_buffer_alloc(struct audit_context *ctx,
ab->skb = nlmsg_new(AUDIT_BUFSIZ, gfp_mask);
if (!ab->skb)
goto err;
+
+ skb_queue_head_init(&ab->skb_list);
+ skb_queue_tail(&ab->skb_list, ab->skb);
+
if (!nlmsg_put(ab->skb, 0, 0, type, 0, 0))
goto err;
@@ -1860,7 +1896,6 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
int type)
{
struct audit_buffer *ab;
- struct audit_stamp stamp;
if (audit_initialized != AUDIT_INITIALIZED)
return NULL;
@@ -1915,14 +1950,14 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
return NULL;
}
- audit_get_stamp(ab->ctx, &stamp);
+ audit_get_stamp(ab->ctx, &ab->stamp);
/* cancel dummy context to enable supporting records */
if (ctx)
ctx->dummy = 0;
audit_log_format(ab, "audit(%llu.%03lu:%u): ",
- (unsigned long long)stamp.ctime.tv_sec,
- stamp.ctime.tv_nsec/1000000,
- stamp.serial);
+ (unsigned long long)ab->stamp.ctime.tv_sec,
+ ab->stamp.ctime.tv_nsec/1000000,
+ ab->stamp.serial);
return ab;
}
@@ -2178,31 +2213,128 @@ void audit_log_key(struct audit_buffer *ab, char *key)
audit_log_format(ab, "(null)");
}
-int audit_log_task_context(struct audit_buffer *ab)
+/**
+ * audit_buffer_aux_new - Add an aux record buffer to the skb list
+ * @ab: audit_buffer
+ * @type: message type
+ *
+ * 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.
+ *
+ * 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);
+}
+
+/**
+ * audit_log_subj_ctx - Add LSM subject information
+ * @ab: audit_buffer
+ * @prop: LSM subject properties.
+ *
+ * Add a subj= field and, if necessary, a AUDIT_MAC_TASK_CONTEXTS record.
+ */
+int audit_log_subj_ctx(struct audit_buffer *ab, struct lsm_prop *prop)
{
- struct lsm_prop prop;
struct lsm_context ctx;
+ char *space = "";
int error;
+ int i;
- security_current_getlsmprop_subj(&prop);
- if (!lsmprop_is_set(&prop))
+ security_current_getlsmprop_subj(prop);
+ if (!lsmprop_is_set(prop))
return 0;
- error = security_lsmprop_to_secctx(&prop, &ctx, LSM_ID_UNDEF);
- if (error < 0) {
- if (error != -EINVAL)
- goto error_path;
+ if (audit_subj_secctx_cnt < 2) {
+ error = security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF);
+ if (error < 0) {
+ if (error != -EINVAL)
+ goto error_path;
+ return 0;
+ }
+ audit_log_format(ab, " subj=%s", ctx.context);
+ security_release_secctx(&ctx);
return 0;
}
-
- audit_log_format(ab, " subj=%s", ctx.context);
- security_release_secctx(&ctx);
+ /* 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;
+
+ for (i = 0; i < audit_subj_secctx_cnt; i++) {
+ error = security_lsmprop_to_secctx(prop, &ctx,
+ audit_subj_lsms[i]->id);
+ if (error < 0) {
+ /*
+ * Don't print anything. An LSM like BPF could
+ * claim to support contexts, but only do so under
+ * certain conditions.
+ */
+ if (error == -EOPNOTSUPP)
+ continue;
+ if (error != -EINVAL)
+ audit_panic("error in audit_log_task_context");
+ } else {
+ audit_log_format(ab, "%ssubj_%s=%s", space,
+ audit_subj_lsms[i]->name, ctx.context);
+ space = " ";
+ security_release_secctx(&ctx);
+ }
+ }
+ audit_buffer_aux_end(ab);
return 0;
error_path:
- audit_panic("error in audit_log_task_context");
+ audit_panic("error in audit_log_subj_ctx");
return error;
}
+EXPORT_SYMBOL(audit_log_subj_ctx);
+
+int audit_log_task_context(struct audit_buffer *ab)
+{
+ struct lsm_prop prop;
+
+ security_current_getlsmprop_subj(&prop);
+ return audit_log_subj_ctx(ab, &prop);
+}
EXPORT_SYMBOL(audit_log_task_context);
void audit_log_d_path_exe(struct audit_buffer *ab,
@@ -2411,6 +2543,26 @@ int audit_signal_info(int sig, struct task_struct *t)
return audit_signal_info_syscall(t);
}
+/**
+ * __audit_log_end - enqueue one audit record
+ * @skb: the buffer to send
+ */
+static void __audit_log_end(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh;
+
+ if (audit_rate_check()) {
+ /* setup the netlink header, see the comments in
+ * kauditd_send_multicast_skb() for length quirks */
+ nlh = nlmsg_hdr(skb);
+ nlh->nlmsg_len = skb->len - NLMSG_HDRLEN;
+
+ /* queue the netlink packet */
+ skb_queue_tail(&audit_queue, skb);
+ } else
+ audit_log_lost("rate limit exceeded");
+}
+
/**
* audit_log_end - end one audit record
* @ab: the audit_buffer
@@ -2423,25 +2575,16 @@ int audit_signal_info(int sig, struct task_struct *t)
void audit_log_end(struct audit_buffer *ab)
{
struct sk_buff *skb;
- struct nlmsghdr *nlh;
if (!ab)
return;
- if (audit_rate_check()) {
- skb = ab->skb;
- ab->skb = NULL;
+ while ((skb = skb_dequeue(&ab->skb_list)))
+ __audit_log_end(skb);
- /* setup the netlink header, see the comments in
- * kauditd_send_multicast_skb() for length quirks */
- nlh = nlmsg_hdr(skb);
- nlh->nlmsg_len = skb->len - NLMSG_HDRLEN;
-
- /* queue the netlink packet and poke the kauditd thread */
- skb_queue_tail(&audit_queue, skb);
+ /* poke the kauditd thread */
+ if (audit_rate_check())
wake_up_interruptible(&kauditd_wait);
- } else
- audit_log_lost("rate limit exceeded");
audit_buffer_free(ab);
}
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 6d6545297ee3..0da652844dd6 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -84,7 +84,6 @@ struct audit_buffer *netlbl_audit_start_common(int type,
struct netlbl_audit *audit_info)
{
struct audit_buffer *audit_buf;
- struct lsm_context ctx;
if (audit_enabled == AUDIT_OFF)
return NULL;
@@ -96,13 +95,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
audit_log_format(audit_buf, "netlabel: auid=%u ses=%u",
from_kuid(&init_user_ns, audit_info->loginuid),
audit_info->sessionid);
-
- if (lsmprop_is_set(&audit_info->prop) &&
- security_lsmprop_to_secctx(&audit_info->prop, &ctx,
- LSM_ID_UNDEF) > 0) {
- audit_log_format(audit_buf, " subj=%s", ctx.context);
- security_release_secctx(&ctx);
- }
+ audit_log_subj_ctx(audit_buf, &audit_info->prop);
return audit_buf;
}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index db8592bed189..4ba6db93e5b0 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -2251,6 +2251,9 @@ static int __init apparmor_init(void)
security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks),
&apparmor_lsmid);
+ /* Inform the audit system that secctx is used */
+ audit_lsm_secctx(&apparmor_lsmid, AUDIT_SECCTX_SUBJECT);
+
/* Report that AppArmor successfully initialized */
apparmor_initialized = 1;
if (aa_g_profile_mode == APPARMOR_COMPLAIN)
diff --git a/security/lsm.h b/security/lsm.h
index d1d54540da98..c432dc0c5e30 100644
--- a/security/lsm.h
+++ b/security/lsm.h
@@ -24,10 +24,6 @@ extern bool lsm_debug;
extern unsigned int lsm_count;
extern const struct lsm_id *lsm_idlist[];
-/* LSM property configuration */
-extern unsigned int lsm_count_prop_subj;
-extern unsigned int lsm_count_prop_obj;
-
/* LSM blob configuration */
extern struct lsm_blob_sizes blob_sizes;
diff --git a/security/lsm_init.c b/security/lsm_init.c
index c2ef4db055db..54166688efff 100644
--- a/security/lsm_init.c
+++ b/security/lsm_init.c
@@ -190,11 +190,6 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
lsm_order[lsm_count] = lsm;
lsm_idlist[lsm_count++] = lsm->id;
- if (lsm->id->flags & LSM_ID_FLG_PROP_SUBJ)
- lsm_count_prop_subj++;
- if (lsm->id->flags & LSM_ID_FLG_PROP_OBJ)
- lsm_count_prop_obj++;
-
lsm_pr_dbg("enabling LSM %s:%s\n", src, lsm->id->name);
}
diff --git a/security/security.c b/security/security.c
index 306860434200..0bb7e0d6ec8b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -78,9 +78,6 @@ bool lsm_debug __ro_after_init;
unsigned int lsm_count __ro_after_init;
const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
-unsigned int lsm_count_prop_subj __ro_after_init;
-unsigned int lsm_count_prop_obj __ro_after_init;
-
struct lsm_blob_sizes blob_sizes;
struct kmem_cache *lsm_file_cache;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1dc4b3987af4..a89561c1fdea 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7516,6 +7516,9 @@ static __init int selinux_init(void)
/* Set the security state for the initial task. */
cred_init_security();
+ /* Inform the audit system that secctx is used */
+ audit_lsm_secctx(&selinux_lsmid, AUDIT_SECCTX_SUBJECT);
+
default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
if (!default_noexec)
pr_notice("SELinux: virtual memory is executable by default\n");
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 47a036e8e452..06603c328079 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5275,6 +5275,9 @@ static __init int smack_init(void)
/* initialize the smack_known_list */
init_smack_known_list();
+ /* Inform the audit system that secctx is used */
+ audit_lsm_secctx(&smack_lsmid, AUDIT_SECCTX_SUBJECT);
+
return 0;
}
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 4/4] Audit: Add record for multiple object contexts
2025-06-07 0:51 ` [PATCH v4 0/4] Audit: Records for multiple security contexts Casey Schaufler
` (2 preceding siblings ...)
2025-06-07 0:51 ` [PATCH v4 3/4] Audit: Add record for multiple task security contexts Casey Schaufler
@ 2025-06-07 0:51 ` Casey Schaufler
2025-06-16 20:54 ` Paul Moore
3 siblings, 1 reply; 10+ messages in thread
From: Casey Schaufler @ 2025-06-07 0:51 UTC (permalink / raw)
To: casey, paul, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux
Create a new audit record AUDIT_MAC_OBJ_CONTEXTS.
An example of the MAC_OBJ_CONTEXTS record is:
type=MAC_OBJ_CONTEXTS
msg=audit(1601152467.009:1050):
obj_selinux=unconfined_u:object_r:user_home_t:s0
When an audit event includes a AUDIT_MAC_OBJ_CONTEXTS record
the "obj=" field in other records in the event will be "obj=?".
An AUDIT_MAC_OBJ_CONTEXTS record is supplied when the system has
multiple security modules that may make access decisions based
on an object security context.
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
---
include/linux/audit.h | 7 +++++
include/uapi/linux/audit.h | 1 +
kernel/audit.c | 58 +++++++++++++++++++++++++++++++++++++-
kernel/auditsc.c | 45 ++++++++---------------------
security/selinux/hooks.c | 3 +-
security/smack/smack_lsm.c | 3 +-
6 files changed, 80 insertions(+), 37 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 5020939fb8bc..c507fdfcf534 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -151,6 +151,7 @@ extern unsigned compat_signal_class[];
/* bit values for audit_lsm_secctx */
#define AUDIT_SECCTX_SUBJECT BIT(0)
+#define AUDIT_SECCTX_OBJECT BIT(1)
struct filename;
@@ -191,6 +192,7 @@ extern void audit_log_path_denied(int type,
extern void audit_log_lost(const char *message);
extern int audit_log_subj_ctx(struct audit_buffer *ab, struct lsm_prop *prop);
+extern int audit_log_obj_ctx(struct audit_buffer *ab, struct lsm_prop *prop);
extern int audit_log_task_context(struct audit_buffer *ab);
extern void audit_log_task_info(struct audit_buffer *ab);
@@ -258,6 +260,11 @@ static inline int audit_log_subj_ctx(struct audit_buffer *ab,
{
return 0;
}
+static inline int audit_log_obj_ctx(struct audit_buffer *ab,
+ struct lsm_prop *prop)
+{
+ return 0;
+}
static inline int audit_log_task_context(struct audit_buffer *ab)
{
return 0;
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 8cad2f307719..14a1c1fe013a 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -149,6 +149,7 @@
#define AUDIT_LANDLOCK_ACCESS 1423 /* Landlock denial */
#define AUDIT_LANDLOCK_DOMAIN 1424 /* Landlock domain status */
#define AUDIT_MAC_TASK_CONTEXTS 1425 /* Multiple LSM task contexts */
+#define AUDIT_MAC_OBJ_CONTEXTS 1426 /* Multiple LSM objext 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 0987b2f391cc..451c36965889 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -85,7 +85,9 @@ static unsigned int audit_net_id;
/* Number of modules that provide a security context.
List of lsms that provide a security context */
static u32 audit_subj_secctx_cnt;
+static u32 audit_obj_secctx_cnt;
static const struct lsm_id *audit_subj_lsms[MAX_LSM_COUNT];
+static const struct lsm_id *audit_obj_lsms[MAX_LSM_COUNT];
/**
* struct audit_net - audit private network namespace data
@@ -305,6 +307,12 @@ void audit_lsm_secctx(const struct lsm_id *lsmid, int flags)
return;
audit_subj_lsms[audit_subj_secctx_cnt++] = lsmid;
}
+ if (flags & AUDIT_SECCTX_OBJECT) {
+ for (i = 0 ; i < audit_obj_secctx_cnt; i++)
+ if (audit_obj_lsms[i] == lsmid)
+ return;
+ audit_obj_lsms[audit_obj_secctx_cnt++] = lsmid;
+ }
}
/**
@@ -1142,7 +1150,6 @@ static int is_audit_feature_set(int i)
return af.features & AUDIT_FEATURE_TO_MASK(i);
}
-
static int audit_get_feature(struct sk_buff *skb)
{
u32 seq;
@@ -2337,6 +2344,55 @@ int audit_log_task_context(struct audit_buffer *ab)
}
EXPORT_SYMBOL(audit_log_task_context);
+int audit_log_obj_ctx(struct audit_buffer *ab, struct lsm_prop *prop)
+{
+ int i;
+ int rc;
+ int error = 0;
+ char *space = "";
+ struct lsm_context ctx;
+
+ if (audit_obj_secctx_cnt < 2) {
+ error = security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF);
+ if (error < 0) {
+ if (error != -EINVAL)
+ goto error_path;
+ return error;
+ }
+ audit_log_format(ab, " obj=%s", ctx.context);
+ security_release_secctx(&ctx);
+ return 0;
+ }
+ audit_log_format(ab, " obj=?");
+ error = audit_buffer_aux_new(ab, AUDIT_MAC_OBJ_CONTEXTS);
+ if (error)
+ goto error_path;
+
+ for (i = 0; i < audit_obj_secctx_cnt; i++) {
+ rc = security_lsmprop_to_secctx(prop, &ctx,
+ audit_obj_lsms[i]->id);
+ if (rc < 0) {
+ audit_log_format(ab, "%sobj_%s=?", space,
+ audit_obj_lsms[i]->name);
+ if (rc != -EINVAL)
+ audit_panic("error in audit_log_obj_ctx");
+ error = rc;
+ } else {
+ audit_log_format(ab, "%sobj_%s=%s", space,
+ audit_obj_lsms[i]->name, ctx.context);
+ security_release_secctx(&ctx);
+ }
+ space = " ";
+ }
+
+ audit_buffer_aux_end(ab);
+ return error;
+
+error_path:
+ audit_panic("error in audit_log_obj_ctx");
+ return error;
+}
+
void audit_log_d_path_exe(struct audit_buffer *ab,
struct mm_struct *mm)
{
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 322d4e27f28e..0c28fa33d099 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1098,7 +1098,6 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
char *comm)
{
struct audit_buffer *ab;
- struct lsm_context ctx;
int rc = 0;
ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
@@ -1108,15 +1107,9 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
from_kuid(&init_user_ns, auid),
from_kuid(&init_user_ns, uid), sessionid);
- if (lsmprop_is_set(prop)) {
- if (security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF) < 0) {
- audit_log_format(ab, " obj=(none)");
- rc = 1;
- } else {
- audit_log_format(ab, " obj=%s", ctx.context);
- security_release_secctx(&ctx);
- }
- }
+ if (lsmprop_is_set(prop) && audit_log_obj_ctx(ab, prop))
+ rc = 1;
+
audit_log_format(ab, " ocomm=");
audit_log_untrustedstring(ab, comm);
audit_log_end(ab);
@@ -1392,16 +1385,8 @@ static void show_special(struct audit_context *context, int *call_panic)
from_kgid(&init_user_ns, context->ipc.gid),
context->ipc.mode);
if (lsmprop_is_set(&context->ipc.oprop)) {
- struct lsm_context lsmctx;
-
- if (security_lsmprop_to_secctx(&context->ipc.oprop,
- &lsmctx,
- LSM_ID_UNDEF) < 0) {
+ if (audit_log_obj_ctx(ab, &context->ipc.oprop))
*call_panic = 1;
- } else {
- audit_log_format(ab, " obj=%s", lsmctx.context);
- security_release_secctx(&lsmctx);
- }
}
if (context->ipc.has_perm) {
audit_log_end(ab);
@@ -1558,18 +1543,9 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
from_kgid(&init_user_ns, n->gid),
MAJOR(n->rdev),
MINOR(n->rdev));
- if (lsmprop_is_set(&n->oprop)) {
- struct lsm_context ctx;
-
- if (security_lsmprop_to_secctx(&n->oprop, &ctx,
- LSM_ID_UNDEF) < 0) {
- if (call_panic)
- *call_panic = 2;
- } else {
- audit_log_format(ab, " obj=%s", ctx.context);
- security_release_secctx(&ctx);
- }
- }
+ if (lsmprop_is_set(&n->oprop) &&
+ audit_log_obj_ctx(ab, &n->oprop))
+ *call_panic = 2;
/* log the audit_names record type */
switch (n->type) {
@@ -1780,15 +1756,16 @@ static void audit_log_exit(void)
axs->target_sessionid[i],
&axs->target_ref[i],
axs->target_comm[i]))
- call_panic = 1;
+ call_panic = 1;
}
if (context->target_pid &&
audit_log_pid_context(context, context->target_pid,
context->target_auid, context->target_uid,
context->target_sessionid,
- &context->target_ref, context->target_comm))
- call_panic = 1;
+ &context->target_ref,
+ context->target_comm))
+ call_panic = 1;
if (context->pwd.dentry && context->pwd.mnt) {
ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a89561c1fdea..0ffe3a7cacf3 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -7517,7 +7517,8 @@ static __init int selinux_init(void)
cred_init_security();
/* Inform the audit system that secctx is used */
- audit_lsm_secctx(&selinux_lsmid, AUDIT_SECCTX_SUBJECT);
+ audit_lsm_secctx(&selinux_lsmid,
+ AUDIT_SECCTX_SUBJECT | AUDIT_SECCTX_OBJECT);
default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
if (!default_noexec)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 06603c328079..b54d93d31600 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -5276,7 +5276,8 @@ static __init int smack_init(void)
init_smack_known_list();
/* Inform the audit system that secctx is used */
- audit_lsm_secctx(&smack_lsmid, AUDIT_SECCTX_SUBJECT);
+ audit_lsm_secctx(&smack_lsmid,
+ AUDIT_SECCTX_SUBJECT | AUDIT_SECCTX_OBJECT);
return 0;
}
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/4] LSM: security_lsmblob_to_secctx module selection
2025-06-07 0:51 ` [PATCH v4 2/4] LSM: security_lsmblob_to_secctx module selection Casey Schaufler
@ 2025-06-16 20:54 ` Paul Moore
0 siblings, 0 replies; 10+ messages in thread
From: Paul Moore @ 2025-06-16 20:54 UTC (permalink / raw)
To: Casey Schaufler, casey, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux
On Jun 6, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> Add a parameter lsmid to security_lsmblob_to_secctx() to identify which
> of the security modules that may be active should provide the security
> context. If the value of lsmid is LSM_ID_UNDEF the first LSM providing
> a hook is used. security_secid_to_secctx() is unchanged, and will
> always report the first LSM providing a hook.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
> include/linux/security.h | 6 ++++--
> kernel/audit.c | 4 ++--
> kernel/auditsc.c | 8 +++++---
> net/netlabel/netlabel_user.c | 3 ++-
> security/security.c | 13 +++++++++++--
> 5 files changed, 24 insertions(+), 10 deletions(-)
...
> diff --git a/security/security.c b/security/security.c
> index 2b9dde02f4de..306860434200 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -3774,6 +3774,7 @@ EXPORT_SYMBOL(security_ismaclabel);
> * security_secid_to_secctx() - Convert a secid to a secctx
> * @secid: secid
> * @cp: the LSM context
> + * @lsmid: which security module to report
> *
> * Convert secid to security context. If @cp is NULL the length of the
> * result will be returned, but no data will be returned. This
You're updating the comment block for the wrong function.
> @@ -3800,9 +3801,17 @@ EXPORT_SYMBOL(security_secid_to_secctx);
> *
> * Return: Return length of data on success, error on failure.
> */
Since you need to update the patch to fix the problem above, it would
probably be a good thing to explain the LSM_ID_UNDEF handling in the
function's comment block as you did in the commit description.
> -int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp)
> +int security_lsmprop_to_secctx(struct lsm_prop *prop, struct lsm_context *cp,
> + int lsmid)
> {
> - return call_int_hook(lsmprop_to_secctx, prop, cp);
> + struct lsm_static_call *scall;
> +
> + lsm_for_each_hook(scall, lsmprop_to_secctx) {
> + if (lsmid != LSM_ID_UNDEF && lsmid != scall->hl->lsmid->id)
> + continue;
> + return scall->hl->hook.lsmprop_to_secctx(prop, cp);
> + }
> + return LSM_RET_DEFAULT(lsmprop_to_secctx);
> }
> EXPORT_SYMBOL(security_lsmprop_to_secctx);
>
> --
> 2.47.0
--
paul-moore.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 3/4] Audit: Add record for multiple task security contexts
2025-06-07 0:51 ` [PATCH v4 3/4] Audit: Add record for multiple task security contexts Casey Schaufler
@ 2025-06-16 20:54 ` Paul Moore
0 siblings, 0 replies; 10+ messages in thread
From: Paul Moore @ 2025-06-16 20:54 UTC (permalink / raw)
To: Casey Schaufler, casey, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux
On Jun 6, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> Replace the single skb pointer in an audit_buffer with a list of
> skb pointers. Add the audit_stamp information to the audit_buffer as
> there's no guarantee that there will be an audit_context containing
> the stamp associated with the event. At audit_log_end() time create
> auxiliary records as have been added to the list. Functions are
> created to manage the skb list in the audit_buffer.
>
> Create a new audit record AUDIT_MAC_TASK_CONTEXTS.
> An example of the MAC_TASK_CONTEXTS record is:
>
> type=MAC_TASK_CONTEXTS
> 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.
>
> Refactor audit_log_task_context(), creating a new audit_log_subj_ctx().
> This is used in netlabel auditing to provide multiple subject security
> contexts as necessary.
>
> Suggested-by: Paul Moore <paul@paul-moore.com>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
> include/linux/audit.h | 16 +++
> include/uapi/linux/audit.h | 1 +
> kernel/audit.c | 207 +++++++++++++++++++++++++++++------
> net/netlabel/netlabel_user.c | 9 +-
> security/apparmor/lsm.c | 3 +
> security/lsm.h | 4 -
> security/lsm_init.c | 5 -
> security/security.c | 3 -
> security/selinux/hooks.c | 3 +
> security/smack/smack_lsm.c | 3 +
> 10 files changed, 202 insertions(+), 52 deletions(-)
...
> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index 0050ef288ab3..5020939fb8bc 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -37,6 +37,8 @@ struct audit_watch;
> struct audit_tree;
> struct sk_buff;
> struct kern_ipc_perm;
> +struct lsm_id;
> +struct lsm_prop;
>
> struct audit_krule {
> u32 pflags;
> @@ -147,6 +149,9 @@ extern unsigned compat_signal_class[];
> #define AUDIT_TTY_ENABLE BIT(0)
> #define AUDIT_TTY_LOG_PASSWD BIT(1)
>
> +/* bit values for audit_lsm_secctx */
> +#define AUDIT_SECCTX_SUBJECT BIT(0)
More on naming below, but how about AUDIT_CFG_LSM_SECCTX_SUBJ?
> diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
> index 9a4ecc9f6dc5..8cad2f307719 100644
> --- a/include/uapi/linux/audit.h
> +++ b/include/uapi/linux/audit.h
> @@ -148,6 +148,7 @@
> #define AUDIT_IPE_POLICY_LOAD 1422 /* IPE policy load */
> #define AUDIT_LANDLOCK_ACCESS 1423 /* Landlock denial */
> #define AUDIT_LANDLOCK_DOMAIN 1424 /* Landlock domain status */
> +#define AUDIT_MAC_TASK_CONTEXTS 1425 /* 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 6bbadb605ca3..0987b2f391cc 100644
> --- a/kernel/audit.c
> +++ b/kernel/audit.c
> @@ -278,6 +286,27 @@ static pid_t auditd_pid_vnr(void)
> return pid;
> }
>
> +/**
> + * audit_lsm_secctx - Identify a security module as providing a secctx.
> + * @lsmid: LSM identity
> + * @flags: which contexts are provided
> + *
> + * Description:
> + * Increments the count of the security modules providing a secctx.
> + * If the LSM id is already in the list leave it alone.
> + */
> +void audit_lsm_secctx(const struct lsm_id *lsmid, int flags)
> +{
> + int i;
> +
> + if (flags & AUDIT_SECCTX_SUBJECT) {
> + for (i = 0 ; i < audit_subj_secctx_cnt; i++)
> + if (audit_subj_lsms[i] == lsmid)
> + return;
> + audit_subj_lsms[audit_subj_secctx_cnt++] = lsmid;
> + }
> +}
Naming is hard ... but since this function has nothing to do with logging
the current state of execution, and is instead more about signaling and
configuring audit, let's try and make that a bit more clear in the
function name while also not getting us stuck with just a secctx config.
How about "audit_cfg_lsm(...)"?
> +/**
> + * audit_log_subj_ctx - Add LSM subject information
> + * @ab: audit_buffer
> + * @prop: LSM subject properties.
> + *
> + * Add a subj= field and, if necessary, a AUDIT_MAC_TASK_CONTEXTS record.
> + */
> +int audit_log_subj_ctx(struct audit_buffer *ab, struct lsm_prop *prop)
> {
> - struct lsm_prop prop;
> struct lsm_context ctx;
> + char *space = "";
> int error;
> + int i;
>
> - security_current_getlsmprop_subj(&prop);
> - if (!lsmprop_is_set(&prop))
> + security_current_getlsmprop_subj(prop);
> + if (!lsmprop_is_set(prop))
> return 0;
>
> - error = security_lsmprop_to_secctx(&prop, &ctx, LSM_ID_UNDEF);
> - if (error < 0) {
> - if (error != -EINVAL)
> - goto error_path;
> + if (audit_subj_secctx_cnt < 2) {
> + error = security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF);
> + if (error < 0) {
> + if (error != -EINVAL)
> + goto error_path;
> + return 0;
> + }
> + audit_log_format(ab, " subj=%s", ctx.context);
> + security_release_secctx(&ctx);
> return 0;
> }
> -
> - audit_log_format(ab, " subj=%s", ctx.context);
> - security_release_secctx(&ctx);
> + /* 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;
> +
> + for (i = 0; i < audit_subj_secctx_cnt; i++) {
> + error = security_lsmprop_to_secctx(prop, &ctx,
> + audit_subj_lsms[i]->id);
> + if (error < 0) {
> + /*
> + * Don't print anything. An LSM like BPF could
> + * claim to support contexts, but only do so under
> + * certain conditions.
> + */
> + if (error == -EOPNOTSUPP)
> + continue;
> + if (error != -EINVAL)
> + audit_panic("error in audit_log_task_context");
Wrong function name, maybe use __func__ or something similar.
> + } else {
> + audit_log_format(ab, "%ssubj_%s=%s", space,
> + audit_subj_lsms[i]->name, ctx.context);
> + space = " ";
> + security_release_secctx(&ctx);
> + }
> + }
> + audit_buffer_aux_end(ab);
> return 0;
>
> error_path:
> - audit_panic("error in audit_log_task_context");
> + audit_panic("error in audit_log_subj_ctx");
> return error;
> }
> +EXPORT_SYMBOL(audit_log_subj_ctx);
...
> @@ -2423,25 +2575,16 @@ int audit_signal_info(int sig, struct task_struct *t)
> void audit_log_end(struct audit_buffer *ab)
> {
> struct sk_buff *skb;
> - struct nlmsghdr *nlh;
>
> if (!ab)
> return;
>
> - if (audit_rate_check()) {
> - skb = ab->skb;
> - ab->skb = NULL;
> + while ((skb = skb_dequeue(&ab->skb_list)))
> + __audit_log_end(skb);
>
> - /* setup the netlink header, see the comments in
> - * kauditd_send_multicast_skb() for length quirks */
> - nlh = nlmsg_hdr(skb);
> - nlh->nlmsg_len = skb->len - NLMSG_HDRLEN;
> -
> - /* queue the netlink packet and poke the kauditd thread */
> - skb_queue_tail(&audit_queue, skb);
> + /* poke the kauditd thread */
> + if (audit_rate_check())
> wake_up_interruptible(&kauditd_wait);
> - } else
> - audit_log_lost("rate limit exceeded");
>
> audit_buffer_free(ab);
> }
Don't make wake_up_interruptible() dependent on audit_rate_check(),
wake up the kauditd thread regardless. Yes, arguably there will be
some cases where the wake will likely be unnecessary, but
audit_rate_check() exists to limit the number of records emitted by
the kernel which is being handled in __audit_log_end(); we don't want
to limit waking the kauditd thread. There is also the issue of the
spin lock which we should try to minimize.
If you're really bothered by calling wake_up_interruptible() without
taking into account if any records have been queued, you could always
have __audit_log_end() return a count/flag/etc. to indicate if any
records have been queued for kauditd, but I suspect that's more
trouble than it's worth.
--
paul-moore.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 4/4] Audit: Add record for multiple object contexts
2025-06-07 0:51 ` [PATCH v4 4/4] Audit: Add record for multiple object contexts Casey Schaufler
@ 2025-06-16 20:54 ` Paul Moore
2025-07-04 20:18 ` Casey Schaufler
0 siblings, 1 reply; 10+ messages in thread
From: Paul Moore @ 2025-06-16 20:54 UTC (permalink / raw)
To: Casey Schaufler, casey, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux
On Jun 6, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> Create a new audit record AUDIT_MAC_OBJ_CONTEXTS.
> An example of the MAC_OBJ_CONTEXTS record is:
>
> type=MAC_OBJ_CONTEXTS
> msg=audit(1601152467.009:1050):
> obj_selinux=unconfined_u:object_r:user_home_t:s0
>
> When an audit event includes a AUDIT_MAC_OBJ_CONTEXTS record
> the "obj=" field in other records in the event will be "obj=?".
> An AUDIT_MAC_OBJ_CONTEXTS record is supplied when the system has
> multiple security modules that may make access decisions based
> on an object security context.
>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
> include/linux/audit.h | 7 +++++
> include/uapi/linux/audit.h | 1 +
> kernel/audit.c | 58 +++++++++++++++++++++++++++++++++++++-
> kernel/auditsc.c | 45 ++++++++---------------------
> security/selinux/hooks.c | 3 +-
> security/smack/smack_lsm.c | 3 +-
> 6 files changed, 80 insertions(+), 37 deletions(-)
...
> diff --git a/kernel/audit.c b/kernel/audit.c
> index 0987b2f391cc..451c36965889 100644
> --- a/kernel/audit.c
> +++ b/kernel/audit.c
> @@ -2337,6 +2344,55 @@ int audit_log_task_context(struct audit_buffer *ab)
> }
> EXPORT_SYMBOL(audit_log_task_context);
>
> +int audit_log_obj_ctx(struct audit_buffer *ab, struct lsm_prop *prop)
> +{
> + int i;
> + int rc;
> + int error = 0;
> + char *space = "";
> + struct lsm_context ctx;
> +
> + if (audit_obj_secctx_cnt < 2) {
> + error = security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF);
> + if (error < 0) {
> + if (error != -EINVAL)
> + goto error_path;
> + return error;
> + }
> + audit_log_format(ab, " obj=%s", ctx.context);
> + security_release_secctx(&ctx);
> + return 0;
> + }
> + audit_log_format(ab, " obj=?");
> + error = audit_buffer_aux_new(ab, AUDIT_MAC_OBJ_CONTEXTS);
> + if (error)
> + goto error_path;
> +
> + for (i = 0; i < audit_obj_secctx_cnt; i++) {
> + rc = security_lsmprop_to_secctx(prop, &ctx,
> + audit_obj_lsms[i]->id);
> + if (rc < 0) {
> + audit_log_format(ab, "%sobj_%s=?", space,
> + audit_obj_lsms[i]->name);
> + if (rc != -EINVAL)
> + audit_panic("error in audit_log_obj_ctx");
> + error = rc;
Do we need the same logic as in audit_log_subj_ctx()?
> + } else {
> + audit_log_format(ab, "%sobj_%s=%s", space,
> + audit_obj_lsms[i]->name, ctx.context);
> + security_release_secctx(&ctx);
> + }
> + space = " ";
> + }
> +
> + audit_buffer_aux_end(ab);
> + return error;
> +
> +error_path:
> + audit_panic("error in audit_log_obj_ctx");
> + return error;
> +}
> +
> void audit_log_d_path_exe(struct audit_buffer *ab,
> struct mm_struct *mm)
> {
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 322d4e27f28e..0c28fa33d099 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -1098,7 +1098,6 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
> char *comm)
> {
> struct audit_buffer *ab;
> - struct lsm_context ctx;
> int rc = 0;
>
> ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
> @@ -1108,15 +1107,9 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
> audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
> from_kuid(&init_user_ns, auid),
> from_kuid(&init_user_ns, uid), sessionid);
> - if (lsmprop_is_set(prop)) {
> - if (security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF) < 0) {
> - audit_log_format(ab, " obj=(none)");
> - rc = 1;
> - } else {
> - audit_log_format(ab, " obj=%s", ctx.context);
> - security_release_secctx(&ctx);
> - }
> - }
> + if (lsmprop_is_set(prop) && audit_log_obj_ctx(ab, prop))
> + rc = 1;
We should probably use the return value from audit_log_obj_ctx().
> audit_log_format(ab, " ocomm=");
> audit_log_untrustedstring(ab, comm);
> audit_log_end(ab);
...
> @@ -1780,15 +1756,16 @@ static void audit_log_exit(void)
> axs->target_sessionid[i],
> &axs->target_ref[i],
> axs->target_comm[i]))
> - call_panic = 1;
> + call_panic = 1;
> }
>
> if (context->target_pid &&
> audit_log_pid_context(context, context->target_pid,
> context->target_auid, context->target_uid,
> context->target_sessionid,
> - &context->target_ref, context->target_comm))
> - call_panic = 1;
> + &context->target_ref,
> + context->target_comm))
> + call_panic = 1;
I appreciate the indent fixes, would you mind pulling this out and
submitting them separately?
--
paul-moore.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 4/4] Audit: Add record for multiple object contexts
2025-06-16 20:54 ` Paul Moore
@ 2025-07-04 20:18 ` Casey Schaufler
2025-07-15 20:40 ` Casey Schaufler
0 siblings, 1 reply; 10+ messages in thread
From: Casey Schaufler @ 2025-07-04 20:18 UTC (permalink / raw)
To: Paul Moore, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux, Casey Schaufler
On 6/16/2025 1:54 PM, Paul Moore wrote:
> On Jun 6, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
>> Create a new audit record AUDIT_MAC_OBJ_CONTEXTS.
>> An example of the MAC_OBJ_CONTEXTS record is:
>>
>> type=MAC_OBJ_CONTEXTS
>> msg=audit(1601152467.009:1050):
>> obj_selinux=unconfined_u:object_r:user_home_t:s0
>>
>> When an audit event includes a AUDIT_MAC_OBJ_CONTEXTS record
>> the "obj=" field in other records in the event will be "obj=?".
>> An AUDIT_MAC_OBJ_CONTEXTS record is supplied when the system has
>> multiple security modules that may make access decisions based
>> on an object security context.
>>
>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>> ---
>> include/linux/audit.h | 7 +++++
>> include/uapi/linux/audit.h | 1 +
>> kernel/audit.c | 58 +++++++++++++++++++++++++++++++++++++-
>> kernel/auditsc.c | 45 ++++++++---------------------
>> security/selinux/hooks.c | 3 +-
>> security/smack/smack_lsm.c | 3 +-
>> 6 files changed, 80 insertions(+), 37 deletions(-)
> ..
>
>> diff --git a/kernel/audit.c b/kernel/audit.c
>> index 0987b2f391cc..451c36965889 100644
>> --- a/kernel/audit.c
>> +++ b/kernel/audit.c
>> @@ -2337,6 +2344,55 @@ int audit_log_task_context(struct audit_buffer *ab)
>> }
>> EXPORT_SYMBOL(audit_log_task_context);
>>
>> +int audit_log_obj_ctx(struct audit_buffer *ab, struct lsm_prop *prop)
>> +{
>> + int i;
>> + int rc;
>> + int error = 0;
>> + char *space = "";
>> + struct lsm_context ctx;
>> +
>> + if (audit_obj_secctx_cnt < 2) {
>> + error = security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF);
>> + if (error < 0) {
>> + if (error != -EINVAL)
>> + goto error_path;
>> + return error;
>> + }
>> + audit_log_format(ab, " obj=%s", ctx.context);
>> + security_release_secctx(&ctx);
>> + return 0;
>> + }
>> + audit_log_format(ab, " obj=?");
>> + error = audit_buffer_aux_new(ab, AUDIT_MAC_OBJ_CONTEXTS);
>> + if (error)
>> + goto error_path;
>> +
>> + for (i = 0; i < audit_obj_secctx_cnt; i++) {
>> + rc = security_lsmprop_to_secctx(prop, &ctx,
>> + audit_obj_lsms[i]->id);
>> + if (rc < 0) {
>> + audit_log_format(ab, "%sobj_%s=?", space,
>> + audit_obj_lsms[i]->name);
>> + if (rc != -EINVAL)
>> + audit_panic("error in audit_log_obj_ctx");
>> + error = rc;
> Do we need the same logic as in audit_log_subj_ctx()?
I seriously debated the issue. Subjects always have data to put in
the aux record. Objects may or may not, in the AppArmor case. Not having
a subject context is an error, not having an object context is interesting,
but not necessarily an error. Hence the different treatment. You can tell
me I'm wrong, and I'll make them consistent.
>
>> + } else {
>> + audit_log_format(ab, "%sobj_%s=%s", space,
>> + audit_obj_lsms[i]->name, ctx.context);
>> + security_release_secctx(&ctx);
>> + }
>> + space = " ";
>> + }
>> +
>> + audit_buffer_aux_end(ab);
>> + return error;
>> +
>> +error_path:
>> + audit_panic("error in audit_log_obj_ctx");
>> + return error;
>> +}
>> +
>> void audit_log_d_path_exe(struct audit_buffer *ab,
>> struct mm_struct *mm)
>> {
>> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
>> index 322d4e27f28e..0c28fa33d099 100644
>> --- a/kernel/auditsc.c
>> +++ b/kernel/auditsc.c
>> @@ -1098,7 +1098,6 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
>> char *comm)
>> {
>> struct audit_buffer *ab;
>> - struct lsm_context ctx;
>> int rc = 0;
>>
>> ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
>> @@ -1108,15 +1107,9 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
>> audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
>> from_kuid(&init_user_ns, auid),
>> from_kuid(&init_user_ns, uid), sessionid);
>> - if (lsmprop_is_set(prop)) {
>> - if (security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF) < 0) {
>> - audit_log_format(ab, " obj=(none)");
>> - rc = 1;
>> - } else {
>> - audit_log_format(ab, " obj=%s", ctx.context);
>> - security_release_secctx(&ctx);
>> - }
>> - }
>> + if (lsmprop_is_set(prop) && audit_log_obj_ctx(ab, prop))
>> + rc = 1;
> We should probably use the return value from audit_log_obj_ctx().
Sure.
>
>> audit_log_format(ab, " ocomm=");
>> audit_log_untrustedstring(ab, comm);
>> audit_log_end(ab);
> ..
>
>> @@ -1780,15 +1756,16 @@ static void audit_log_exit(void)
>> axs->target_sessionid[i],
>> &axs->target_ref[i],
>> axs->target_comm[i]))
>> - call_panic = 1;
>> + call_panic = 1;
>> }
>>
>> if (context->target_pid &&
>> audit_log_pid_context(context, context->target_pid,
>> context->target_auid, context->target_uid,
>> context->target_sessionid,
>> - &context->target_ref, context->target_comm))
>> - call_panic = 1;
>> + &context->target_ref,
>> + context->target_comm))
>> + call_panic = 1;
> I appreciate the indent fixes, would you mind pulling this out and
> submitting them separately?
Sure.
>
> --
> paul-moore.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 4/4] Audit: Add record for multiple object contexts
2025-07-04 20:18 ` Casey Schaufler
@ 2025-07-15 20:40 ` Casey Schaufler
0 siblings, 0 replies; 10+ messages in thread
From: Casey Schaufler @ 2025-07-15 20:40 UTC (permalink / raw)
To: Paul Moore, eparis, linux-security-module, audit
Cc: jmorris, serge, keescook, john.johansen, penguin-kernel,
stephen.smalley.work, linux-kernel, selinux, Casey Schaufler
On 7/4/2025 1:18 PM, Casey Schaufler wrote:
> On 6/16/2025 1:54 PM, Paul Moore wrote:
>> On Jun 6, 2025 Casey Schaufler <casey@schaufler-ca.com> wrote:
>>> Create a new audit record AUDIT_MAC_OBJ_CONTEXTS.
>>> An example of the MAC_OBJ_CONTEXTS record is:
>>>
>>> type=MAC_OBJ_CONTEXTS
>>> msg=audit(1601152467.009:1050):
>>> obj_selinux=unconfined_u:object_r:user_home_t:s0
>>>
>>> When an audit event includes a AUDIT_MAC_OBJ_CONTEXTS record
>>> the "obj=" field in other records in the event will be "obj=?".
>>> An AUDIT_MAC_OBJ_CONTEXTS record is supplied when the system has
>>> multiple security modules that may make access decisions based
>>> on an object security context.
>>>
>>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>>> ---
>>> include/linux/audit.h | 7 +++++
>>> include/uapi/linux/audit.h | 1 +
>>> kernel/audit.c | 58 +++++++++++++++++++++++++++++++++++++-
>>> kernel/auditsc.c | 45 ++++++++---------------------
>>> security/selinux/hooks.c | 3 +-
>>> security/smack/smack_lsm.c | 3 +-
>>> 6 files changed, 80 insertions(+), 37 deletions(-)
>> ..
>>
>>> diff --git a/kernel/audit.c b/kernel/audit.c
>>> index 0987b2f391cc..451c36965889 100644
>>> --- a/kernel/audit.c
>>> +++ b/kernel/audit.c
>>> @@ -2337,6 +2344,55 @@ int audit_log_task_context(struct audit_buffer *ab)
>>> }
>>> EXPORT_SYMBOL(audit_log_task_context);
>>>
>>> +int audit_log_obj_ctx(struct audit_buffer *ab, struct lsm_prop *prop)
>>> +{
>>> + int i;
>>> + int rc;
>>> + int error = 0;
>>> + char *space = "";
>>> + struct lsm_context ctx;
>>> +
>>> + if (audit_obj_secctx_cnt < 2) {
>>> + error = security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF);
>>> + if (error < 0) {
>>> + if (error != -EINVAL)
>>> + goto error_path;
>>> + return error;
>>> + }
>>> + audit_log_format(ab, " obj=%s", ctx.context);
>>> + security_release_secctx(&ctx);
>>> + return 0;
>>> + }
>>> + audit_log_format(ab, " obj=?");
>>> + error = audit_buffer_aux_new(ab, AUDIT_MAC_OBJ_CONTEXTS);
>>> + if (error)
>>> + goto error_path;
>>> +
>>> + for (i = 0; i < audit_obj_secctx_cnt; i++) {
>>> + rc = security_lsmprop_to_secctx(prop, &ctx,
>>> + audit_obj_lsms[i]->id);
>>> + if (rc < 0) {
>>> + audit_log_format(ab, "%sobj_%s=?", space,
>>> + audit_obj_lsms[i]->name);
>>> + if (rc != -EINVAL)
>>> + audit_panic("error in audit_log_obj_ctx");
>>> + error = rc;
>> Do we need the same logic as in audit_log_subj_ctx()?
> I seriously debated the issue. Subjects always have data to put in
> the aux record. Objects may or may not, in the AppArmor case. Not having
> a subject context is an error, not having an object context is interesting,
> but not necessarily an error. Hence the different treatment. You can tell
> me I'm wrong, and I'll make them consistent.
>
>>> + } else {
>>> + audit_log_format(ab, "%sobj_%s=%s", space,
>>> + audit_obj_lsms[i]->name, ctx.context);
>>> + security_release_secctx(&ctx);
>>> + }
>>> + space = " ";
>>> + }
>>> +
>>> + audit_buffer_aux_end(ab);
>>> + return error;
>>> +
>>> +error_path:
>>> + audit_panic("error in audit_log_obj_ctx");
>>> + return error;
>>> +}
>>> +
>>> void audit_log_d_path_exe(struct audit_buffer *ab,
>>> struct mm_struct *mm)
>>> {
>>> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
>>> index 322d4e27f28e..0c28fa33d099 100644
>>> --- a/kernel/auditsc.c
>>> +++ b/kernel/auditsc.c
>>> @@ -1098,7 +1098,6 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
>>> char *comm)
>>> {
>>> struct audit_buffer *ab;
>>> - struct lsm_context ctx;
>>> int rc = 0;
>>>
>>> ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
>>> @@ -1108,15 +1107,9 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
>>> audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
>>> from_kuid(&init_user_ns, auid),
>>> from_kuid(&init_user_ns, uid), sessionid);
>>> - if (lsmprop_is_set(prop)) {
>>> - if (security_lsmprop_to_secctx(prop, &ctx, LSM_ID_UNDEF) < 0) {
>>> - audit_log_format(ab, " obj=(none)");
>>> - rc = 1;
>>> - } else {
>>> - audit_log_format(ab, " obj=%s", ctx.context);
>>> - security_release_secctx(&ctx);
>>> - }
>>> - }
>>> + if (lsmprop_is_set(prop) && audit_log_obj_ctx(ab, prop))
>>> + rc = 1;
>> We should probably use the return value from audit_log_obj_ctx().
> Sure.
On further inspection, the callers of audit_log_obj_ctx() don't
do anything with the return code, and similar functions have their
returns treated the same way. Unless there's a major rework of the
audit code there isn't any value in "using" the return code.
>>> audit_log_format(ab, " ocomm=");
>>> audit_log_untrustedstring(ab, comm);
>>> audit_log_end(ab);
>> ..
>>
>>> @@ -1780,15 +1756,16 @@ static void audit_log_exit(void)
>>> axs->target_sessionid[i],
>>> &axs->target_ref[i],
>>> axs->target_comm[i]))
>>> - call_panic = 1;
>>> + call_panic = 1;
>>> }
>>>
>>> if (context->target_pid &&
>>> audit_log_pid_context(context, context->target_pid,
>>> context->target_auid, context->target_uid,
>>> context->target_sessionid,
>>> - &context->target_ref, context->target_comm))
>>> - call_panic = 1;
>>> + &context->target_ref,
>>> + context->target_comm))
>>> + call_panic = 1;
>> I appreciate the indent fixes, would you mind pulling this out and
>> submitting them separately?
> Sure.
>
>> --
>> paul-moore.com
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-07-15 21:10 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20250607005134.10488-1-casey.ref@schaufler-ca.com>
2025-06-07 0:51 ` [PATCH v4 0/4] Audit: Records for multiple security contexts Casey Schaufler
2025-06-07 0:51 ` [PATCH v4 1/4] Audit: Create audit_stamp structure Casey Schaufler
2025-06-07 0:51 ` [PATCH v4 2/4] LSM: security_lsmblob_to_secctx module selection Casey Schaufler
2025-06-16 20:54 ` Paul Moore
2025-06-07 0:51 ` [PATCH v4 3/4] Audit: Add record for multiple task security contexts Casey Schaufler
2025-06-16 20:54 ` Paul Moore
2025-06-07 0:51 ` [PATCH v4 4/4] Audit: Add record for multiple object contexts Casey Schaufler
2025-06-16 20:54 ` Paul Moore
2025-07-04 20:18 ` Casey Schaufler
2025-07-15 20:40 ` Casey Schaufler
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).