On 2021-05-21 16:19, Paul Moore wrote: > On Thu, May 13, 2021 at 4:32 PM Casey Schaufler <casey@xxxxxxxxxxxxxxxx> wrote: > > Create a new audit record type to contain the subject information > > when there are multiple security modules that require such data. > > This record is linked with the same timestamp and serial number > > using the audit_alloc_local() mechanism. > > The record is linked with the other associated records into a single > event, it doesn't matter if it gets the timestamp/serial from > audit_alloc_local() or an existing audit event, e.g. ongoing syscall. I had similar concerns this would be misunderstood... > > The record is produced only in cases where there is more than one > > security module with a process "context". > > In cases where this record is produced the subj= fields of > > other records in the audit event will be set to "subj=?". > > > > An example of the MAC_TASK_CONTEXTS (1420) record is: > > > > type=UNKNOWN[1420] > > msg=audit(1600880931.832:113) > > subj_apparmor==unconfined > > It should be just a single "=" in the line above. > > > subj_smack=_ > > > > There will be a subj_$LSM= entry for each security module > > LSM that supports the secid_to_secctx and secctx_to_secid > > hooks. The BPF security module implements secid/secctx > > translation hooks, so it has to be considered to provide a > > secctx even though it may not actually do so. > > > > Signed-off-by: Casey Schaufler <casey@xxxxxxxxxxxxxxxx> > > To: paul@xxxxxxxxxxxxxx > > To: linux-audit@xxxxxxxxxx > > To: rgb@xxxxxxxxxx > > Cc: netdev@xxxxxxxxxxxxxxx > > --- > > drivers/android/binder.c | 2 +- > > include/linux/audit.h | 24 ++++++++ > > include/linux/security.h | 16 ++++- > > include/net/netlabel.h | 3 +- > > include/net/scm.h | 2 +- > > include/net/xfrm.h | 13 +++- > > include/uapi/linux/audit.h | 1 + > > kernel/audit.c | 80 ++++++++++++++++++------- > > kernel/audit.h | 3 + > > kernel/auditfilter.c | 6 +- > > kernel/auditsc.c | 75 ++++++++++++++++++++--- > > net/ipv4/ip_sockglue.c | 2 +- > > net/netfilter/nf_conntrack_netlink.c | 4 +- > > net/netfilter/nf_conntrack_standalone.c | 2 +- > > net/netfilter/nfnetlink_queue.c | 2 +- > > net/netlabel/netlabel_domainhash.c | 4 +- > > net/netlabel/netlabel_unlabeled.c | 24 ++++---- > > net/netlabel/netlabel_user.c | 20 ++++--- > > net/netlabel/netlabel_user.h | 6 +- > > net/xfrm/xfrm_policy.c | 10 ++-- > > net/xfrm/xfrm_state.c | 20 ++++--- > > security/integrity/ima/ima_api.c | 7 ++- > > security/integrity/integrity_audit.c | 6 +- > > security/security.c | 46 +++++++++----- > > security/smack/smackfs.c | 3 +- > > 25 files changed, 274 insertions(+), 107 deletions(-) > > ... > > > diff --git a/include/linux/audit.h b/include/linux/audit.h > > index 97cd7471e572..229cd71fbf09 100644 > > --- a/include/linux/audit.h > > +++ b/include/linux/audit.h > > @@ -386,6 +395,19 @@ static inline void audit_ptrace(struct task_struct *t) > > __audit_ptrace(t); > > } > > > > +static inline struct audit_context *audit_alloc_for_lsm(gfp_t gfp) > > +{ > > + struct audit_context *context = audit_context(); > > + > > + if (context) > > + return context; > > + > > + if (lsm_multiple_contexts()) > > + return audit_alloc_local(gfp); > > + > > + return NULL; > > +} > > See my other comments, but this seems wrong at face value. The > additional LSM record should happen as part of the existing audit log > functions. Right. The only time a local context should be necessary is if there is a group of records that should be divorced from a syscall or that has no syscall (or other similar context). > > diff --git a/include/linux/security.h b/include/linux/security.h > > index 0129400ff6e9..ddab456e93d3 100644 > > --- a/include/linux/security.h > > +++ b/include/linux/security.h > > @@ -182,6 +182,8 @@ struct lsmblob { > > #define LSMBLOB_INVALID -1 /* Not a valid LSM slot number */ > > #define LSMBLOB_NEEDED -2 /* Slot requested on initialization */ > > #define LSMBLOB_NOT_NEEDED -3 /* Slot not requested */ > > +#define LSMBLOB_DISPLAY -4 /* Use the "display" slot */ > > +#define LSMBLOB_FIRST -5 /* Use the default "display" slot */ > > > > /** > > * lsmblob_init - initialize an lsmblob structure > > @@ -248,6 +250,15 @@ static inline u32 lsmblob_value(const struct lsmblob *blob) > > return 0; > > } > > > > +static inline bool lsm_multiple_contexts(void) > > +{ > > +#ifdef CONFIG_SECURITY > > + return lsm_slot_to_name(1) != NULL; > > +#else > > + return false; > > +#endif > > +} > > + > > /* These functions are in security/commoncap.c */ > > extern int cap_capable(const struct cred *cred, struct user_namespace *ns, > > int cap, unsigned int opts); > > @@ -578,7 +589,8 @@ int security_setprocattr(const char *lsm, 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(struct lsmblob *blob, struct lsmcontext *cp); > > +int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp, > > + int display); > > int security_secctx_to_secid(const char *secdata, u32 seclen, > > struct lsmblob *blob); > > void security_release_secctx(struct lsmcontext *cp); > > @@ -1433,7 +1445,7 @@ static inline int security_ismaclabel(const char *name) > > } > > > > static inline int security_secid_to_secctx(struct lsmblob *blob, > > - struct lsmcontext *cp) > > + struct lsmcontext *cp, int display) > > { > > return -EOPNOTSUPP; > > } > > diff --git a/include/net/netlabel.h b/include/net/netlabel.h > > index 73fc25b4042b..9bc1f969a25d 100644 > > --- a/include/net/netlabel.h > > +++ b/include/net/netlabel.h > > @@ -97,7 +97,8 @@ struct calipso_doi; > > > > /* NetLabel audit information */ > > struct netlbl_audit { > > - u32 secid; > > + struct audit_context *localcontext; > > + struct lsmblob lsmdata; > > kuid_t loginuid; > > unsigned int sessionid; > > }; > > diff --git a/include/net/scm.h b/include/net/scm.h > > index b77a52f93389..f4d567d4885e 100644 > > --- a/include/net/scm.h > > +++ b/include/net/scm.h > > @@ -101,7 +101,7 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc > > * and the infrastructure will know which it is. > > */ > > lsmblob_init(&lb, scm->secid); > > - err = security_secid_to_secctx(&lb, &context); > > + err = security_secid_to_secctx(&lb, &context, LSMBLOB_DISPLAY); > > > > if (!err) { > > put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, context.len, > > diff --git a/include/net/xfrm.h b/include/net/xfrm.h > > index c58a6d4eb610..f8ad20d34498 100644 > > --- a/include/net/xfrm.h > > +++ b/include/net/xfrm.h > > @@ -669,13 +669,22 @@ struct xfrm_spi_skb_cb { > > #define XFRM_SPI_SKB_CB(__skb) ((struct xfrm_spi_skb_cb *)&((__skb)->cb[0])) > > > > #ifdef CONFIG_AUDITSYSCALL > > -static inline struct audit_buffer *xfrm_audit_start(const char *op) > > +static inline struct audit_buffer *xfrm_audit_start(const char *op, > > + struct audit_context **lac) > > { > > + struct audit_context *context; > > struct audit_buffer *audit_buf = NULL; > > > > if (audit_enabled == AUDIT_OFF) > > return NULL; > > - audit_buf = audit_log_start(audit_context(), GFP_ATOMIC, > > + context = audit_context(); > > + if (lac != NULL) { > > + if (lsm_multiple_contexts() && context == NULL) > > + context = audit_alloc_local(GFP_ATOMIC); > > + *lac = context; > > + } > > Okay, we've got a disconnect here regarding "audit contexts" and > "local contexts", skip down below where I attempt to explain things a > little more but basically if there is a place that uses this pattern: > > audit_log_start(audit_context(), ...); > > ... you don't need, or want, a "local context". You might need a > local context if you see the following pattern: > > audit_log_start(NULL, ...); > > The "local context" idea is a hack and should be avoided whenever > possible; if you have an existing audit context from a syscall, or > something else, you *really* should use it ... or have a *really* good > explanation as to why you can not. Yes, what Paul said. Examples include network events that have no syscall related to them or a user record that isn't really related to the syscall that produced it. > > + audit_buf = audit_log_start(context, GFP_ATOMIC, > > AUDIT_MAC_IPSEC_EVENT); > > if (audit_buf == NULL) > > return NULL; > > > diff --git a/kernel/audit.c b/kernel/audit.c > > index 841123390d41..60c027d7759c 100644 > > --- a/kernel/audit.c > > +++ b/kernel/audit.c > > @@ -386,10 +386,12 @@ void audit_log_lost(const char *message) > > static int audit_log_config_change(char *function_name, u32 new, u32 old, > > int allow_changes) > > { > > + struct audit_context *context; > > struct audit_buffer *ab; > > int rc = 0; > > > > - ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE); > > + context = audit_alloc_for_lsm(GFP_KERNEL); > > + ab = audit_log_start(context, GFP_KERNEL, AUDIT_CONFIG_CHANGE); > > Use the existing context, don't create your own, it breaks the record > associations in the audit event stream. Agreed. > > if (unlikely(!ab)) > > return rc; > > audit_log_format(ab, "op=set %s=%u old=%u ", function_name, new, old); > > @@ -398,7 +400,7 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old, > > if (rc) > > allow_changes = 0; /* Something weird, deny request */ > > audit_log_format(ab, " res=%d", allow_changes); > > - audit_log_end(ab); > > + audit_log_end_local(ab, context); > > More on this below, but we really should just use audit_log_end(), > "local contexts" are not special, the are regular audit contexts ... > although if they are used properly (limited scope) you do need to free > them when you are done. I was a bit puzzled about this before and had the same concerns. > > return rc; > > } > > > > > @@ -1357,7 +1355,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) > > if (err) > > break; > > } > > - audit_log_user_recv_msg(&ab, msg_type); > > + lcontext = audit_alloc_for_lsm(GFP_KERNEL); > > + audit_log_common_recv_msg(lcontext, &ab, msg_type); > > Same. > > > if (msg_type != AUDIT_USER_TTY) { > > /* ensure NULL termination */ > > str[data_len - 1] = '\0'; > > @@ -1370,7 +1369,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) > > data_len--; > > audit_log_n_untrustedstring(ab, str, data_len); > > } > > - audit_log_end(ab); > > + audit_log_end_local(ab, lcontext); > > Same. > > > } > > break; > > case AUDIT_ADD_RULE: > > @@ -1378,13 +1377,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) > > if (data_len < sizeof(struct audit_rule_data)) > > return -EINVAL; > > if (audit_enabled == AUDIT_LOCKED) { > > - audit_log_common_recv_msg(audit_context(), &ab, > > + lcontext = audit_alloc_for_lsm(GFP_KERNEL); > > + audit_log_common_recv_msg(lcontext, &ab, > > AUDIT_CONFIG_CHANGE); > > audit_log_format(ab, " op=%s audit_enabled=%d res=0", > > msg_type == AUDIT_ADD_RULE ? > > "add_rule" : "remove_rule", > > audit_enabled); > > - audit_log_end(ab); > > + audit_log_end_local(ab, lcontext); > > Same. I'm going to stop calling these out, I think you get the idea. > > > @@ -2396,6 +2415,21 @@ void audit_log_end(struct audit_buffer *ab) > > audit_buffer_free(ab); > > } > > > > +/** > > + * audit_log_end_local - end one audit record with local context > > + * @ab: the audit_buffer > > + * @context: the local context > > + * > > + * Emit an LSM context record if appropriate, then end the audit event > > + * in the usual way. > > + */ > > +void audit_log_end_local(struct audit_buffer *ab, struct audit_context *context) > > +{ > > + audit_log_end(ab); > > + audit_log_lsm_common(context); > > + audit_free_local(context); > > +} > > Eeesh, no, not this please. It was this that I found hard to follow and justify. > First, some background on audit contexts and the idea of a "local > context" as we have been using it in the audit container ID work, > which is where this originated. An audit context contains a few > things, but likely the most important for this discussion is the audit > event timestamp and serial number (I may refer to this combo as just a > "timestamp" in the future); this timestamp/serial is shared across all > of the audit records that make up this audit event, linking them > together. A shared timestamp is what allows you to group an open() > SYSCALL record with the PATH record that provides the file's pathname > info. How about a "postmark"? :-) (Yes, timestamp works...) > While there are some exceptions in the current code, most audit events > occur as a result of a syscall, and their audit context in this case > is the syscall's audit context (see the open() example above), but > there are some cases being discussed where we have an audit event that > does not occur as a result of a syscall but there is a need to group > multiple audit records together in a single event. This is where the > "local context" comes into play, it allows us to create an audit > context outside of a syscall and share that context across multiple > audit records, allowing the records to share a timestamp/serial and > grouping them together as a single audit event in the audit stream. > > While a function like audit_alloc_local() make sense, there really > shouldn't be an audit_log_end_local() function, the normal > audit_log_end() function should be used. Exactly. > Does that make sense? > > > diff --git a/kernel/audit.h b/kernel/audit.h > > index 27ef690afd30..5ad0c6819aa8 100644 > > --- a/kernel/audit.h > > +++ b/kernel/audit.h > > @@ -100,6 +100,7 @@ struct audit_context { > > int dummy; /* must be the first element */ > > int in_syscall; /* 1 if task is in a syscall */ > > bool local; /* local context needed */ > > + bool lsmdone; /* multiple security reported */ > > "lsmdone" doesn't seem consistent with the comment, how about > "lsm_multi" or something similar? > > > enum audit_state state, current_state; > > unsigned int serial; /* serial number for record */ > > int major; /* syscall number */ > > > diff --git a/kernel/auditsc.c b/kernel/auditsc.c > > index d4e061f95da8..55509faf5341 100644 > > --- a/kernel/auditsc.c > > +++ b/kernel/auditsc.c > > @@ -1013,6 +1013,13 @@ void audit_free_context(struct audit_context *context) > > } > > EXPORT_SYMBOL(audit_free_context); > > > > +void audit_free_local(struct audit_context *context) > > +{ > > + if (context && context->local) > > + audit_free_context(context); > > +} > > +EXPORT_SYMBOL(audit_free_local); > > We don't need this function, just use audit_free_context(). A "local > context" is the same as a non-local context; what makes a context > "local" is the scope of the audit context (local function scope vs > syscall scope) and nothing else. Agreed. > > @@ -1504,6 +1512,47 @@ static void audit_log_proctitle(void) > > audit_log_end(ab); > > } > > > > +void audit_log_lsm_common(struct audit_context *context) > > +{ > > + struct audit_buffer *ab; > > + struct lsmcontext lsmdata; > > + bool sep = false; > > + int error; > > + int i; > > + > > + if (!lsm_multiple_contexts() || context == NULL || > > + !lsmblob_is_set(&context->lsm)) > > + return; > > + > > + ab = audit_log_start(context, GFP_ATOMIC, AUDIT_MAC_TASK_CONTEXTS); > > + if (!ab) > > + return; /* audit_panic or being filtered */ > > We should be consistent with our use of audit_panic() when we bail on > error; we use it below, but not here - why? > > > + for (i = 0; i < LSMBLOB_ENTRIES; i++) { > > + if (context->lsm.secid[i] == 0) > > + continue; > > + error = security_secid_to_secctx(&context->lsm, &lsmdata, i); > > + if (error && error != -EINVAL) { > > + audit_panic("error in audit_log_lsm"); > > + return; > > + } > > + > > + audit_log_format(ab, "%ssubj_%s=%s", sep ? " " : "", > > + lsm_slot_to_name(i), lsmdata.context); > > + sep = true; > > + security_release_secctx(&lsmdata); > > + } > > + audit_log_end(ab); > > + context->lsmdone = true; > > Maybe I missed it, but why do we need this flag? This is partly what confused me earlier... > > +} > > + > > +void audit_log_lsm(struct audit_context *context) > > +{ > > + if (!context->lsmdone) > > + audit_log_lsm_common(context); > > +} > > I think I was distracted with the local context issue and I've lost > track of the details here, perhaps it's best to fix the local context > issue first (that should be a big change to this patch) and then we > can take another look. I got distracted by the local context issues too earlier... Sorry, this feedback would have been more useful earlier. I never completed that review and got pulled off to other priorities... > paul moore - RGB -- Richard Guy Briggs <rgb@xxxxxxxxxx> Sr. S/W Engineer, Kernel Security, Base Operating Systems Remote, Ottawa, Red Hat Canada IRC: rgb, SunRaycer Voice: +1.647.777.2635, Internal: (81) 32635