diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-09 10:13:03 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-09 10:13:03 -0800 |
| commit | 698749164aa53cc313248efd2dc1c25dcf25c99c (patch) | |
| tree | 0d6b5c2348b44fb418e65faf20148934bc707a8b | |
| parent | 37b4fbf8dbdfb694f2972d1bd7fcd36304a520dd (diff) | |
| parent | 76489955c6d4a065ca69dc88faf7a50a59b66f35 (diff) | |
Merge tag 'audit-pr-20260203' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit
Pull audit updates from Paul Moore:
- Improve the NETFILTER_PKT audit records
Add source and destination ports to the NETFILTER_PKT audit records
while also consolidating a lot of the code into a new, singular
audit_log_nf_skb() function. This new approach to structuring the
NETFILTER_PKT record generation should eliminate some unnecessary
overhead when audit is not built into the kernel.
- Update the audit syscall classifier code
Add the listxattrat(), getxattrat(), and fchmodat2() syscall to the
audit code which classifies syscalls into categories of operations,
e.g. "read" or "change attributes".
- Move the syscall classifier declarations into audit_arch.h
Shuffle around some header file declarations to resolve some sparse
warnings.
* tag 'audit-pr-20260203' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit:
audit: move the compat_xxx_class[] extern declarations to audit_arch.h
audit: add missing syscalls to read class
audit: include source and destination ports to NETFILTER_PKT
audit: add audit_log_nf_skb helper function
audit: add fchmodat2() to change attributes class
| -rw-r--r-- | include/asm-generic/audit_change_attr.h | 3 | ||||
| -rw-r--r-- | include/asm-generic/audit_read.h | 6 | ||||
| -rw-r--r-- | include/linux/audit.h | 14 | ||||
| -rw-r--r-- | include/linux/audit_arch.h | 7 | ||||
| -rw-r--r-- | kernel/audit.c | 159 | ||||
| -rw-r--r-- | net/netfilter/nft_log.c | 58 | ||||
| -rw-r--r-- | net/netfilter/xt_AUDIT.c | 58 |
7 files changed, 185 insertions, 120 deletions
diff --git a/include/asm-generic/audit_change_attr.h b/include/asm-generic/audit_change_attr.h index cc840537885f..ddd90bbe40df 100644 --- a/include/asm-generic/audit_change_attr.h +++ b/include/asm-generic/audit_change_attr.h @@ -26,6 +26,9 @@ __NR_fremovexattr, __NR_fchownat, __NR_fchmodat, #endif +#ifdef __NR_fchmodat2 +__NR_fchmodat2, +#endif #ifdef __NR_chown32 __NR_chown32, __NR_fchown32, diff --git a/include/asm-generic/audit_read.h b/include/asm-generic/audit_read.h index 7bb7b5a83ae2..fb9991f53fb6 100644 --- a/include/asm-generic/audit_read.h +++ b/include/asm-generic/audit_read.h @@ -4,9 +4,15 @@ __NR_readlink, #endif __NR_quotactl, __NR_listxattr, +#ifdef __NR_listxattrat +__NR_listxattrat, +#endif __NR_llistxattr, __NR_flistxattr, __NR_getxattr, +#ifdef __NR_getxattrat +__NR_getxattrat, +#endif __NR_lgetxattr, __NR_fgetxattr, #ifdef __NR_readlinkat diff --git a/include/linux/audit.h b/include/linux/audit.h index 536f8ee8da81..04d16895c56a 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -128,12 +128,6 @@ enum audit_nfcfgop { extern int __init audit_register_class(int class, unsigned *list); extern int audit_classify_syscall(int abi, unsigned syscall); extern int audit_classify_arch(int arch); -/* only for compat system calls */ -extern unsigned compat_write_class[]; -extern unsigned compat_read_class[]; -extern unsigned compat_dir_class[]; -extern unsigned compat_chattr_class[]; -extern unsigned compat_signal_class[]; /* audit_names->type values */ #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ @@ -195,6 +189,8 @@ 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); +extern int audit_log_nf_skb(struct audit_buffer *ab, + const struct sk_buff *skb, u8 nfproto); extern int audit_update_lsm_rules(void); @@ -272,6 +268,12 @@ static inline int audit_log_task_context(struct audit_buffer *ab) static inline void audit_log_task_info(struct audit_buffer *ab) { } +static inline int audit_log_nf_skb(struct audit_buffer *ab, + const struct sk_buff *skb, u8 nfproto) +{ + return 0; +} + static inline kuid_t audit_get_loginuid(struct task_struct *tsk) { return INVALID_UID; diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h index 0e34d673ef17..2b8153791e6a 100644 --- a/include/linux/audit_arch.h +++ b/include/linux/audit_arch.h @@ -23,4 +23,11 @@ enum auditsc_class_t { extern int audit_classify_compat_syscall(int abi, unsigned syscall); +/* only for compat system calls */ +extern unsigned compat_write_class[]; +extern unsigned compat_read_class[]; +extern unsigned compat_dir_class[]; +extern unsigned compat_chattr_class[]; +extern unsigned compat_signal_class[]; + #endif diff --git a/kernel/audit.c b/kernel/audit.c index 26a332ffb1b8..39c4f26c484d 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -58,6 +58,9 @@ #include <linux/freezer.h> #include <linux/pid_namespace.h> #include <net/netns/generic.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <linux/sctp.h> #include "audit.h" @@ -2488,6 +2491,162 @@ void audit_log_path_denied(int type, const char *operation) audit_log_end(ab); } +int audit_log_nf_skb(struct audit_buffer *ab, + const struct sk_buff *skb, u8 nfproto) +{ + /* find the IP protocol in the case of NFPROTO_BRIDGE */ + if (nfproto == NFPROTO_BRIDGE) { + switch (eth_hdr(skb)->h_proto) { + case htons(ETH_P_IP): + nfproto = NFPROTO_IPV4; + break; + case htons(ETH_P_IPV6): + nfproto = NFPROTO_IPV6; + break; + default: + goto unknown_proto; + } + } + + switch (nfproto) { + case NFPROTO_IPV4: { + struct iphdr iph; + const struct iphdr *ih; + + ih = skb_header_pointer(skb, skb_network_offset(skb), + sizeof(iph), &iph); + if (!ih) + return -ENOMEM; + + switch (ih->protocol) { + case IPPROTO_TCP: { + struct tcphdr _tcph; + const struct tcphdr *th; + + th = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_tcph), &_tcph); + if (!th) + return -ENOMEM; + + audit_log_format(ab, " saddr=%pI4 daddr=%pI4 proto=%hhu sport=%hu dport=%hu", + &ih->saddr, &ih->daddr, ih->protocol, + ntohs(th->source), ntohs(th->dest)); + break; + } + case IPPROTO_UDP: + case IPPROTO_UDPLITE: { + struct udphdr _udph; + const struct udphdr *uh; + + uh = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_udph), &_udph); + if (!uh) + return -ENOMEM; + + audit_log_format(ab, " saddr=%pI4 daddr=%pI4 proto=%hhu sport=%hu dport=%hu", + &ih->saddr, &ih->daddr, ih->protocol, + ntohs(uh->source), ntohs(uh->dest)); + break; + } + case IPPROTO_SCTP: { + struct sctphdr _sctph; + const struct sctphdr *sh; + + sh = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_sctph), &_sctph); + if (!sh) + return -ENOMEM; + + audit_log_format(ab, " saddr=%pI4 daddr=%pI4 proto=%hhu sport=%hu dport=%hu", + &ih->saddr, &ih->daddr, ih->protocol, + ntohs(sh->source), ntohs(sh->dest)); + break; + } + default: + audit_log_format(ab, " saddr=%pI4 daddr=%pI4 proto=%hhu", + &ih->saddr, &ih->daddr, ih->protocol); + } + + break; + } + case NFPROTO_IPV6: { + struct ipv6hdr iph; + const struct ipv6hdr *ih; + u8 nexthdr; + __be16 frag_off; + + ih = skb_header_pointer(skb, skb_network_offset(skb), + sizeof(iph), &iph); + if (!ih) + return -ENOMEM; + + nexthdr = ih->nexthdr; + ipv6_skip_exthdr(skb, skb_network_offset(skb) + sizeof(iph), + &nexthdr, &frag_off); + + switch (nexthdr) { + case IPPROTO_TCP: { + struct tcphdr _tcph; + const struct tcphdr *th; + + th = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_tcph), &_tcph); + if (!th) + return -ENOMEM; + + audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu sport=%hu dport=%hu", + &ih->saddr, &ih->daddr, nexthdr, + ntohs(th->source), ntohs(th->dest)); + break; + } + case IPPROTO_UDP: + case IPPROTO_UDPLITE: { + struct udphdr _udph; + const struct udphdr *uh; + + uh = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_udph), &_udph); + if (!uh) + return -ENOMEM; + + audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu sport=%hu dport=%hu", + &ih->saddr, &ih->daddr, nexthdr, + ntohs(uh->source), ntohs(uh->dest)); + break; + } + case IPPROTO_SCTP: { + struct sctphdr _sctph; + const struct sctphdr *sh; + + sh = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_sctph), &_sctph); + if (!sh) + return -ENOMEM; + + audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu sport=%hu dport=%hu", + &ih->saddr, &ih->daddr, nexthdr, + ntohs(sh->source), ntohs(sh->dest)); + break; + } + default: + audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu", + &ih->saddr, &ih->daddr, nexthdr); + } + + break; + } + default: + goto unknown_proto; + } + + return 0; + +unknown_proto: + audit_log_format(ab, " saddr=? daddr=? proto=?"); + return -EPFNOSUPPORT; +} +EXPORT_SYMBOL(audit_log_nf_skb); + /* global counter which is incremented every time something logs in */ static atomic_t session_id = ATOMIC_INIT(0); diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c index e35588137995..bf01cf8a8907 100644 --- a/net/netfilter/nft_log.c +++ b/net/netfilter/nft_log.c @@ -26,46 +26,10 @@ struct nft_log { char *prefix; }; -static bool audit_ip4(struct audit_buffer *ab, struct sk_buff *skb) -{ - struct iphdr _iph; - const struct iphdr *ih; - - ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_iph), &_iph); - if (!ih) - return false; - - audit_log_format(ab, " saddr=%pI4 daddr=%pI4 proto=%hhu", - &ih->saddr, &ih->daddr, ih->protocol); - - return true; -} - -static bool audit_ip6(struct audit_buffer *ab, struct sk_buff *skb) -{ - struct ipv6hdr _ip6h; - const struct ipv6hdr *ih; - u8 nexthdr; - __be16 frag_off; - - ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_ip6h), &_ip6h); - if (!ih) - return false; - - nexthdr = ih->nexthdr; - ipv6_skip_exthdr(skb, skb_network_offset(skb) + sizeof(_ip6h), &nexthdr, &frag_off); - - audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu", - &ih->saddr, &ih->daddr, nexthdr); - - return true; -} - static void nft_log_eval_audit(const struct nft_pktinfo *pkt) { struct sk_buff *skb = pkt->skb; struct audit_buffer *ab; - int fam = -1; if (!audit_enabled) return; @@ -76,27 +40,7 @@ static void nft_log_eval_audit(const struct nft_pktinfo *pkt) audit_log_format(ab, "mark=%#x", skb->mark); - switch (nft_pf(pkt)) { - case NFPROTO_BRIDGE: - switch (eth_hdr(skb)->h_proto) { - case htons(ETH_P_IP): - fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1; - break; - case htons(ETH_P_IPV6): - fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1; - break; - } - break; - case NFPROTO_IPV4: - fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1; - break; - case NFPROTO_IPV6: - fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1; - break; - } - - if (fam == -1) - audit_log_format(ab, " saddr=? daddr=? proto=-1"); + audit_log_nf_skb(ab, skb, nft_pf(pkt)); audit_log_end(ab); } diff --git a/net/netfilter/xt_AUDIT.c b/net/netfilter/xt_AUDIT.c index b6a015aee0ce..4c18606b8654 100644 --- a/net/netfilter/xt_AUDIT.c +++ b/net/netfilter/xt_AUDIT.c @@ -28,46 +28,10 @@ MODULE_ALIAS("ip6t_AUDIT"); MODULE_ALIAS("ebt_AUDIT"); MODULE_ALIAS("arpt_AUDIT"); -static bool audit_ip4(struct audit_buffer *ab, struct sk_buff *skb) -{ - struct iphdr _iph; - const struct iphdr *ih; - - ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_iph), &_iph); - if (!ih) - return false; - - audit_log_format(ab, " saddr=%pI4 daddr=%pI4 proto=%hhu", - &ih->saddr, &ih->daddr, ih->protocol); - - return true; -} - -static bool audit_ip6(struct audit_buffer *ab, struct sk_buff *skb) -{ - struct ipv6hdr _ip6h; - const struct ipv6hdr *ih; - u8 nexthdr; - __be16 frag_off; - - ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_ip6h), &_ip6h); - if (!ih) - return false; - - nexthdr = ih->nexthdr; - ipv6_skip_exthdr(skb, skb_network_offset(skb) + sizeof(_ip6h), &nexthdr, &frag_off); - - audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu", - &ih->saddr, &ih->daddr, nexthdr); - - return true; -} - static unsigned int audit_tg(struct sk_buff *skb, const struct xt_action_param *par) { struct audit_buffer *ab; - int fam = -1; if (audit_enabled == AUDIT_OFF) goto errout; @@ -77,27 +41,7 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par) audit_log_format(ab, "mark=%#x", skb->mark); - switch (xt_family(par)) { - case NFPROTO_BRIDGE: - switch (eth_hdr(skb)->h_proto) { - case htons(ETH_P_IP): - fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1; - break; - case htons(ETH_P_IPV6): - fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1; - break; - } - break; - case NFPROTO_IPV4: - fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1; - break; - case NFPROTO_IPV6: - fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1; - break; - } - - if (fam == -1) - audit_log_format(ab, " saddr=? daddr=? proto=-1"); + audit_log_nf_skb(ab, skb, xt_family(par)); audit_log_end(ab); |
