Skip to content

Commit

Permalink
Audit: Add record for multiple process LSM attributes
Browse files Browse the repository at this point in the history
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 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
        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@schaufler-ca.com>
To: paul@paul-moore.com
To: linux-audit@redhat.com
To: rgb@redhat.com
Cc: netdev@vger.kernel.org
  • Loading branch information
cschaufler authored and intel-lab-lkp committed Jun 16, 2021
1 parent c6c28a6 commit d534cd7
Show file tree
Hide file tree
Showing 23 changed files with 221 additions and 90 deletions.
2 changes: 1 addition & 1 deletion drivers/android/binder.c
Original file line number Diff line number Diff line change
Expand Up @@ -2722,7 +2722,7 @@ static void binder_transaction(struct binder_proc *proc,
* case well anyway.
*/
security_task_getsecid_obj(proc->tsk, &blob);
ret = security_secid_to_secctx(&blob, &lsmctx);
ret = security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_DISPLAY);
if (ret) {
return_error = BR_FAILED_REPLY;
return_error_param = ret;
Expand Down
16 changes: 16 additions & 0 deletions include/linux/audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ extern int audit_alloc(struct task_struct *task);
extern void __audit_free(struct task_struct *task);
extern struct audit_context *audit_alloc_local(gfp_t gfpflags);
extern void audit_free_context(struct audit_context *context);
extern void audit_free_local(struct audit_context *context);
extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
extern void __audit_syscall_exit(int ret_success, long ret_value);
Expand Down Expand Up @@ -386,6 +387,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;
}

/* Private API (for audit.c only) */
extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
Expand Down Expand Up @@ -560,6 +574,8 @@ extern int audit_signals;
}
static inline void audit_free_context(struct audit_context *context)
{ }
static inline void audit_free_local(struct audit_context *context)
{ }
static inline int audit_alloc(struct task_struct *task)
{
return 0;
Expand Down
16 changes: 14 additions & 2 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion include/net/netlabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ struct calipso_doi;

/* NetLabel audit information */
struct netlbl_audit {
u32 secid;
struct lsmblob lsmdata;
kuid_t loginuid;
unsigned int sessionid;
};
Expand Down
2 changes: 1 addition & 1 deletion include/net/scm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
13 changes: 11 additions & 2 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

audit_buf = audit_log_start(context, GFP_ATOMIC,
AUDIT_MAC_IPSEC_EVENT);
if (audit_buf == NULL)
return NULL;
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,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 contexts */

#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
Expand Down
90 changes: 71 additions & 19 deletions kernel/audit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
if (unlikely(!ab))
return rc;
audit_log_format(ab, "op=set %s=%u old=%u ", function_name, new, old);
Expand All @@ -399,6 +401,7 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old,
allow_changes = 0; /* Something weird, deny request */
audit_log_format(ab, " res=%d", allow_changes);
audit_log_end(ab);
audit_free_local(context);
return rc;
}

Expand Down Expand Up @@ -1072,12 +1075,6 @@ static void audit_log_common_recv_msg(struct audit_context *context,
audit_log_task_context(*ab);
}

static inline void audit_log_user_recv_msg(struct audit_buffer **ab,
u16 msg_type)
{
audit_log_common_recv_msg(NULL, ab, msg_type);
}

int is_audit_feature_set(int i)
{
return af.features & AUDIT_FEATURE_TO_MASK(i);
Expand Down Expand Up @@ -1190,6 +1187,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
struct audit_buffer *ab;
u16 msg_type = nlh->nlmsg_type;
struct audit_sig_info *sig_data;
struct audit_context *lcontext;

err = audit_netlink_ok(skb, msg_type);
if (err)
Expand Down Expand Up @@ -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);
if (msg_type != AUDIT_USER_TTY) {
/* ensure NULL termination */
str[data_len - 1] = '\0';
Expand All @@ -1371,20 +1370,23 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
audit_log_n_untrustedstring(ab, str, data_len);
}
audit_log_end(ab);
audit_free_local(lcontext);
}
break;
case AUDIT_ADD_RULE:
case AUDIT_DEL_RULE:
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_free_local(lcontext);
return -EPERM;
}
err = audit_rule_change(msg_type, seq, data, data_len);
Expand All @@ -1394,10 +1396,11 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
break;
case AUDIT_TRIM:
audit_trim_trees();
audit_log_common_recv_msg(audit_context(), &ab,
AUDIT_CONFIG_CHANGE);
lcontext = audit_alloc_for_lsm(GFP_KERNEL);
audit_log_common_recv_msg(lcontext, &ab, AUDIT_CONFIG_CHANGE);
audit_log_format(ab, " op=trim res=1");
audit_log_end(ab);
audit_free_local(lcontext);
break;
case AUDIT_MAKE_EQUIV: {
void *bufp = data;
Expand Down Expand Up @@ -1425,14 +1428,15 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
/* OK, here comes... */
err = audit_tag_tree(old, new);

audit_log_common_recv_msg(audit_context(), &ab,
AUDIT_CONFIG_CHANGE);
lcontext = audit_alloc_for_lsm(GFP_KERNEL);
audit_log_common_recv_msg(lcontext, &ab, AUDIT_CONFIG_CHANGE);
audit_log_format(ab, " op=make_equiv old=");
audit_log_untrustedstring(ab, old);
audit_log_format(ab, " new=");
audit_log_untrustedstring(ab, new);
audit_log_format(ab, " res=%d", !err);
audit_log_end(ab);
audit_free_local(lcontext);
kfree(old);
kfree(new);
break;
Expand All @@ -1443,7 +1447,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)

if (lsmblob_is_set(&audit_sig_lsm)) {
err = security_secid_to_secctx(&audit_sig_lsm,
&context);
&context, LSMBLOB_FIRST);
if (err)
return err;
}
Expand Down Expand Up @@ -1498,13 +1502,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
old.enabled = t & AUDIT_TTY_ENABLE;
old.log_passwd = !!(t & AUDIT_TTY_LOG_PASSWD);

audit_log_common_recv_msg(audit_context(), &ab,
AUDIT_CONFIG_CHANGE);
lcontext = audit_alloc_for_lsm(GFP_KERNEL);
audit_log_common_recv_msg(lcontext, &ab, AUDIT_CONFIG_CHANGE);
audit_log_format(ab, " op=tty_set old-enabled=%d new-enabled=%d"
" old-log_passwd=%d new-log_passwd=%d res=%d",
old.enabled, s.enabled, old.log_passwd,
s.log_passwd, !err);
audit_log_end(ab);
audit_free_local(lcontext);
break;
}
default:
Expand Down Expand Up @@ -1550,6 +1555,7 @@ static void audit_receive(struct sk_buff *skb)
/* Log information about who is connecting to the audit multicast socket */
static void audit_log_multicast(int group, const char *op, int err)
{
struct audit_context *context;
const struct cred *cred;
struct tty_struct *tty;
char comm[sizeof(current->comm)];
Expand All @@ -1558,7 +1564,8 @@ static void audit_log_multicast(int group, const char *op, int err)
if (!audit_enabled)
return;

ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_EVENT_LISTENER);
context = audit_alloc_for_lsm(GFP_KERNEL);
ab = audit_log_start(context, GFP_KERNEL, AUDIT_EVENT_LISTENER);
if (!ab)
return;

Expand All @@ -1577,6 +1584,7 @@ static void audit_log_multicast(int group, const char *op, int err)
audit_log_d_path_exe(ab, current->mm); /* exe= */
audit_log_format(ab, " nl-mcgrp=%d op=%s res=%d", group, op, !err);
audit_log_end(ab);
audit_free_local(context);
}

/* Run custom bind function on netlink socket group connect or bind requests. */
Expand Down Expand Up @@ -2128,6 +2136,36 @@ void audit_log_key(struct audit_buffer *ab, char *key)
audit_log_format(ab, "(null)");
}

static void audit_log_lsm(struct audit_context *context, struct lsmblob *blob)
{
struct audit_buffer *ab;
struct lsmcontext lsmdata;
bool sep = false;
int error;
int i;

ab = audit_log_start(context, GFP_ATOMIC, AUDIT_MAC_TASK_CONTEXTS);
if (!ab)
return; /* audit_panic or being filtered */

for (i = 0; i < LSMBLOB_ENTRIES; i++) {
if (blob->secid[i] == 0)
continue;
error = security_secid_to_secctx(blob, &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);
}

int audit_log_task_context(struct audit_buffer *ab)
{
int error;
Expand All @@ -2138,7 +2176,18 @@ int audit_log_task_context(struct audit_buffer *ab)
if (!lsmblob_is_set(&blob))
return 0;

error = security_secid_to_secctx(&blob, &context);
/*
* If there is more than one security module that has a
* subject "context" it's necessary to put the subject data
* into a separate record to maintain compatibility.
*/
if (lsm_multiple_contexts()) {
audit_log_format(ab, " subj=?");
audit_log_lsm(ab->ctx, &blob);
return 0;
}

error = security_secid_to_secctx(&blob, &context, LSMBLOB_FIRST);
if (error) {
if (error != -EINVAL)
goto error_path;
Expand Down Expand Up @@ -2274,14 +2323,16 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
unsigned int oldsessionid,
unsigned int sessionid, int rc)
{
struct audit_context *context;
struct audit_buffer *ab;
uid_t uid, oldloginuid, loginuid;
struct tty_struct *tty;

if (!audit_enabled)
return;

ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_LOGIN);
context = audit_alloc_for_lsm(GFP_KERNEL);
ab = audit_log_start(context, GFP_KERNEL, AUDIT_LOGIN);
if (!ab)
return;

Expand All @@ -2297,6 +2348,7 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
oldsessionid, sessionid, !rc);
audit_put_tty(tty);
audit_log_end(ab);
audit_free_local(context);
}

/**
Expand Down
Loading

0 comments on commit d534cd7

Please sign in to comment.