Reduce logging of nftables events to a level similar to iptables. Restore the table field to list the table, adding the generation. Indicate the op as the most significant operation in the event. A couple of sample events: type=PROCTITLE msg=audit(2021-03-18 09:30:49.801:143) : proctitle=/usr/bin/python3 -s /usr/sbin/firewalld --nofork --nopid type=SYSCALL msg=audit(2021-03-18 09:30:49.801:143) : arch=x86_64 syscall=sendmsg success=yes exit=172 a0=0x6 a1=0x7ffdcfcbe650 a2=0x0 a3=0x7ffdcfcbd52c items=0 ppid=1 pid=367 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=roo t sgid=root fsgid=root tty=(none) ses=unset comm=firewalld exe=/usr/bin/python3.9 subj=system_u:system_r:firewalld_t:s0 key=(null) type=NETFILTER_CFG msg=audit(2021-03-18 09:30:49.801:143) : table=firewalld:2 family=ipv6 entries=1 op=nft_register_table pid=367 subj=system_u:system_r:firewalld_t:s0 comm=firewalld type=NETFILTER_CFG msg=audit(2021-03-18 09:30:49.801:143) : table=firewalld:2 family=ipv4 entries=1 op=nft_register_table pid=367 subj=system_u:system_r:firewalld_t:s0 comm=firewalld type=NETFILTER_CFG msg=audit(2021-03-18 09:30:49.801:143) : table=firewalld:2 family=inet entries=1 op=nft_register_table pid=367 subj=system_u:system_r:firewalld_t:s0 comm=firewalld type=PROCTITLE msg=audit(2021-03-18 09:30:49.839:144) : proctitle=/usr/bin/python3 -s /usr/sbin/firewalld --nofork --nopid type=SYSCALL msg=audit(2021-03-18 09:30:49.839:144) : arch=x86_64 syscall=sendmsg success=yes exit=22792 a0=0x6 a1=0x7ffdcfcbe650 a2=0x0 a3=0x7ffdcfcbd52c items=0 ppid=1 pid=367 auid=unset uid=root gid=root euid=root suid=root fsuid=root egid=r oot sgid=root fsgid=root tty=(none) ses=unset comm=firewalld exe=/usr/bin/python3.9 subj=system_u:system_r:firewalld_t:s0 key=(null) type=NETFILTER_CFG msg=audit(2021-03-18 09:30:49.839:144) : table=firewalld:3 family=ipv6 entries=30 op=nft_register_chain pid=367 subj=system_u:system_r:firewalld_t:s0 comm=firewalld type=NETFILTER_CFG msg=audit(2021-03-18 09:30:49.839:144) : table=firewalld:3 family=ipv4 entries=30 op=nft_register_chain pid=367 subj=system_u:system_r:firewalld_t:s0 comm=firewalld type=NETFILTER_CFG msg=audit(2021-03-18 09:30:49.839:144) : table=firewalld:3 family=inet entries=165 op=nft_register_chain pid=367 subj=system_u:system_r:firewalld_t:s0 comm=firewalld The issue was originally documented in https://github.com/linux-audit/audit-kernel/issues/124 Signed-off-by: Richard Guy Briggs <rgb@xxxxxxxxxx> --- include/linux/audit.h | 29 ++++++++ net/netfilter/nf_tables_api.c | 132 +++++++++++++--------------------- 2 files changed, 78 insertions(+), 83 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 82b7c1116a85..bba6a0386742 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -118,6 +118,35 @@ enum audit_nfcfgop { AUDIT_NFT_OP_INVALID, }; +static const u8 nft2audit_op[] = { // enum nf_tables_msg_types + /* NFT_MSG_NEWTABLE */ AUDIT_NFT_OP_TABLE_REGISTER, + /* NFT_MSG_GETTABLE */ AUDIT_NFT_OP_INVALID, + /* NFT_MSG_DELTABLE */ AUDIT_NFT_OP_TABLE_UNREGISTER, + /* NFT_MSG_NEWCHAIN */ AUDIT_NFT_OP_CHAIN_REGISTER, + /* NFT_MSG_GETCHAIN */ AUDIT_NFT_OP_INVALID, + /* NFT_MSG_DELCHAIN */ AUDIT_NFT_OP_CHAIN_UNREGISTER, + /* NFT_MSG_NEWRULE */ AUDIT_NFT_OP_RULE_REGISTER, + /* NFT_MSG_GETRULE */ AUDIT_NFT_OP_INVALID, + /* NFT_MSG_DELRULE */ AUDIT_NFT_OP_RULE_UNREGISTER, + /* NFT_MSG_NEWSET */ AUDIT_NFT_OP_SET_REGISTER, + /* NFT_MSG_GETSET */ AUDIT_NFT_OP_INVALID, + /* NFT_MSG_DELSET */ AUDIT_NFT_OP_SET_UNREGISTER, + /* NFT_MSG_NEWSETELEM */ AUDIT_NFT_OP_SETELEM_REGISTER, + /* NFT_MSG_GETSETELEM */ AUDIT_NFT_OP_INVALID, + /* NFT_MSG_DELSETELEM */ AUDIT_NFT_OP_SETELEM_UNREGISTER, + /* NFT_MSG_NEWGEN */ AUDIT_NFT_OP_GEN_REGISTER, + /* NFT_MSG_GETGEN */ AUDIT_NFT_OP_INVALID, + /* NFT_MSG_TRACE */ AUDIT_NFT_OP_INVALID, + /* NFT_MSG_NEWOBJ */ AUDIT_NFT_OP_OBJ_REGISTER, + /* NFT_MSG_GETOBJ */ AUDIT_NFT_OP_INVALID, + /* NFT_MSG_DELOBJ */ AUDIT_NFT_OP_OBJ_UNREGISTER, + /* NFT_MSG_GETOBJ_RESET */ AUDIT_NFT_OP_OBJ_RESET, + /* NFT_MSG_NEWFLOWTABLE */ AUDIT_NFT_OP_FLOWTABLE_REGISTER, + /* NFT_MSG_GETFLOWTABLE */ AUDIT_NFT_OP_INVALID, + /* NFT_MSG_DELFLOWTABLE */ AUDIT_NFT_OP_FLOWTABLE_UNREGISTER, + /* NFT_MSG_MAX */ AUDIT_NFT_OP_INVALID, +}; + extern int is_audit_feature_set(int which); extern int __init audit_register_class(int class, unsigned *list); diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 8d5aa0ac45f4..ad31d8876169 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -709,17 +709,6 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event) { struct sk_buff *skb; int err; - char *buf = kasprintf(GFP_KERNEL, "%s:%llu;?:0", - ctx->table->name, ctx->table->handle); - - audit_log_nfcfg(buf, - ctx->family, - ctx->table->use, - event == NFT_MSG_NEWTABLE ? - AUDIT_NFT_OP_TABLE_REGISTER : - AUDIT_NFT_OP_TABLE_UNREGISTER, - GFP_KERNEL); - kfree(buf); if (!ctx->report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES)) @@ -1476,18 +1465,6 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event) { struct sk_buff *skb; int err; - char *buf = kasprintf(GFP_KERNEL, "%s:%llu;%s:%llu", - ctx->table->name, ctx->table->handle, - ctx->chain->name, ctx->chain->handle); - - audit_log_nfcfg(buf, - ctx->family, - ctx->chain->use, - event == NFT_MSG_NEWCHAIN ? - AUDIT_NFT_OP_CHAIN_REGISTER : - AUDIT_NFT_OP_CHAIN_UNREGISTER, - GFP_KERNEL); - kfree(buf); if (!ctx->report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES)) @@ -2838,18 +2815,6 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx, { struct sk_buff *skb; int err; - char *buf = kasprintf(GFP_KERNEL, "%s:%llu;%s:%llu", - ctx->table->name, ctx->table->handle, - ctx->chain->name, ctx->chain->handle); - - audit_log_nfcfg(buf, - ctx->family, - rule->handle, - event == NFT_MSG_NEWRULE ? - AUDIT_NFT_OP_RULE_REGISTER : - AUDIT_NFT_OP_RULE_UNREGISTER, - GFP_KERNEL); - kfree(buf); if (!ctx->report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES)) @@ -3882,18 +3847,6 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx, struct sk_buff *skb; u32 portid = ctx->portid; int err; - char *buf = kasprintf(gfp_flags, "%s:%llu;%s:%llu", - ctx->table->name, ctx->table->handle, - set->name, set->handle); - - audit_log_nfcfg(buf, - ctx->family, - set->field_count, - event == NFT_MSG_NEWSET ? - AUDIT_NFT_OP_SET_REGISTER : - AUDIT_NFT_OP_SET_UNREGISTER, - gfp_flags); - kfree(buf); if (!ctx->report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES)) @@ -5067,18 +5020,6 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx, u32 portid = ctx->portid; struct sk_buff *skb; int err; - char *buf = kasprintf(GFP_KERNEL, "%s:%llu;%s:%llu", - ctx->table->name, ctx->table->handle, - set->name, set->handle); - - audit_log_nfcfg(buf, - ctx->family, - set->handle, - event == NFT_MSG_NEWSETELEM ? - AUDIT_NFT_OP_SETELEM_REGISTER : - AUDIT_NFT_OP_SETELEM_UNREGISTER, - GFP_KERNEL); - kfree(buf); if (!ctx->report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES)) return; @@ -6278,12 +6219,11 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb) filter->type != NFT_OBJECT_UNSPEC && obj->ops->type->type != filter->type) goto cont; - if (reset) { char *buf = kasprintf(GFP_ATOMIC, - "%s:%llu;?:0", + "%s:%u", table->name, - table->handle); + net->nft.base_seq); audit_log_nfcfg(buf, family, @@ -6404,8 +6344,8 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk, reset = true; if (reset) { - char *buf = kasprintf(GFP_ATOMIC, "%s:%llu;?:0", - table->name, table->handle); + char *buf = kasprintf(GFP_ATOMIC, "%s:%u", + table->name, net->nft.base_seq); audit_log_nfcfg(buf, family, @@ -6492,15 +6432,15 @@ void nft_obj_notify(struct net *net, const struct nft_table *table, { struct sk_buff *skb; int err; - char *buf = kasprintf(gfp, "%s:%llu;?:0", - table->name, table->handle); + char *buf = kasprintf(gfp, "%s:%u", + table->name, net->nft.base_seq); audit_log_nfcfg(buf, family, obj->handle, event == NFT_MSG_NEWOBJ ? - AUDIT_NFT_OP_OBJ_REGISTER : - AUDIT_NFT_OP_OBJ_UNREGISTER, + AUDIT_NFT_OP_OBJ_REGISTER : + AUDIT_NFT_OP_OBJ_UNREGISTER, gfp); kfree(buf); @@ -7300,18 +7240,6 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx, { struct sk_buff *skb; int err; - char *buf = kasprintf(GFP_KERNEL, "%s:%llu;%s:%llu", - flowtable->table->name, flowtable->table->handle, - flowtable->name, flowtable->handle); - - audit_log_nfcfg(buf, - ctx->family, - flowtable->hooknum, - event == NFT_MSG_NEWFLOWTABLE ? - AUDIT_NFT_OP_FLOWTABLE_REGISTER : - AUDIT_NFT_OP_FLOWTABLE_UNREGISTER, - GFP_KERNEL); - kfree(buf); if (!ctx->report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES)) @@ -7432,9 +7360,6 @@ static void nf_tables_gen_notify(struct net *net, struct sk_buff *skb, struct sk_buff *skb2; int err; - audit_log_nfcfg("?:0;?:0", 0, net->nft.base_seq, - AUDIT_NFT_OP_GEN_REGISTER, GFP_KERNEL); - if (!nlmsg_report(nlh) && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES)) return; @@ -7979,6 +7904,14 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) struct nft_trans_elem *te; struct nft_chain *chain; struct nft_table *table; + struct audit_log_nftdata { + struct nft_table *table; + int entries; + int op; + struct audit_log_nftdata *next; + } ad = { NULL, 0, 0, NULL }, *adp, *adnext; +#define AUNFTABLENAMELEN (NFT_TABLE_MAXNAMELEN + 22) + char aubuf[AUNFTABLENAMELEN]; int err; if (list_empty(&net->nft.commit_list)) { @@ -8173,12 +8106,45 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) } break; } + adp = &ad; + if (!adp->table) { + adp->table = trans->ctx.table; + adp->entries = 1; + adp->op = trans->msg_type; + } else { + adnext = &ad; + do { + adp = adnext; + if (adp->table == trans->ctx.table) + goto found; + adnext = adp->next; + } while (adnext); + adp->next = kzalloc(sizeof(*adp->next), GFP_KERNEL); + adp = adp->next; + adp->table = trans->ctx.table; +found: + adp->entries++; + if (!adp->op || adp->op > trans->msg_type) + adp->op = trans->msg_type; + } } nft_commit_notify(net, NETLINK_CB(skb).portid); nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN); nf_tables_commit_release(net); + adp = &ad; + while (adp && adp->table) { + snprintf(aubuf, AUNFTABLENAMELEN, "%s:%u", adp->table->name, + net->nft.base_seq); + audit_log_nfcfg(aubuf, adp->table->family, adp->entries, + nft2audit_op[adp->op], GFP_KERNEL); + adnext = adp->next; + if (adp != &ad) + kfree(adp); + adp = adnext; + } + return 0; } -- 2.27.0