On 10 August 2026 21:49:45 BST, Ricardo Robaina <[email protected]> wrote: >On Mon, Aug 10, 2026 at 1:28 PM Bradley Morgan <[email protected]> wrote: >> >> On 10 August 2026 16:19:10 BST, Ricardo Robaina <[email protected]> >> wrote: >> >On Mon, Aug 10, 2026 at 10:32 AM Bradley Morgan <[email protected]> >wrote: >> >> >> >> Hi Ricardo, >> >> >> >> > - nlh->nlmsg_len = skb->len; >> >> > + nlh->nlmsg_len = copy->len; >> >> >> >> Fine. skb_copy() does skb_put(n, skb->len) and nothing touches >> >> copy->len in between, so the two are always identical. >> >> Which is also why "safer" is a bit of a stretch, it prevents nothing. >> >> Feel free to bikeshed the changelog wording on that. >> >> >> > >> >Thanks for reviewing this patch, Bradley. I agree with you on the >wording. >> > >> >> np. >> >> >> If you ever want a more interesting cleanup here, the real quirk is >> >> the line above: the unicast path sets nlmsg_len to skb->len minus >> >> NLMSG_HDRLEN, this one uses the full length. >> > >> >That's interesting, maybe moving the nlmsg_len fixup out of >> >__audit_log_end() would be better. I'll look into it. >> > >> >> Hmmm.. perhaps it will. I will suggest a fix: >> >> From 776375d625cd9cb138f7a6f876861bf428ae1e6c Mon Sep 17 00:00:00 2001 >> From: Bradley Morgan <[email protected]> >> Date: Mon, 10 Aug 2026 16:26:06 +0000 >> Subject: [PATCH] audit: move the nlmsg_len fixup from __audit_log_end() >to >> send time >> >> The auditd breakage (nlmsg_len set to the payload length instead of >> the full message length) is applied in __audit_log_end() when the >> record is queued. That forces kauditd_send_multicast_skb() to deep >> copy every record and undo the length on the copy, so the multicast >> group still sees a standard netlink message. >> >> Instead, finalize the header with the standard full length at queue >> time and apply the auditd length right before the unicast send in >> kauditd_send_queue(). Records stay standard netlink messages while >> they sit in the queues, and the multicast copy no longer needs its >> own fixup. The deep copy itself stays, since the auditd length >> rewrite lands in the shared data region after the copy is already >> handed to the listeners. >> >> auditd sees the same bytes as before. The fixup is computed from >> skb->len, which does not change between queueing and sending, so >> records that come back through the retry and hold queues get the same >> value again. Reply and rule list skbs are built with nlmsg_put() and >> sent on other paths, none of those are touched. >> >> This came out of the "use copied skb length" thread, where moving the >> fixup was suggested as the more interesting cleanup. >> >> Signed-off-by: Bradley Morgan <[email protected]> >> --- >> kernel/audit.c | 38 ++++++++++++++++++++++---------------- >> 1 file changed, 22 insertions(+), 16 deletions(-) >> >> diff --git a/kernel/audit.c b/kernel/audit.c >> index 9412af9144bc..5b6528fc6eb5 100644 >> --- a/kernel/audit.c >> +++ b/kernel/audit.c >> @@ -802,6 +802,15 @@ static int kauditd_send_queue(struct sock *sk, u32 >portid, >> if (skb_hook) >> (*skb_hook)(skb); >> >> + /* >> + * auditd expects nlmsg_len to be the payload length >rather >> + * than the full message length. Apply the breakage >here at >> + * send time so the record stays a standard netlink >message >> + * while queued and while it is copied for the multicast >> + * group above. >> + */ >> + nlmsg_hdr(skb)->nlmsg_len = skb->len - NLMSG_HDRLEN; >> + >> /* can we send to anyone via unicast? */ >> if (!sk) { >> if (err_hook) >> @@ -849,7 +858,6 @@ static void kauditd_send_multicast_skb(struct >sk_buff *skb) >> { >> struct sk_buff *copy; >> struct sock *sock = audit_get_sk(&init_net); >> - struct nlmsghdr *nlh; >> >> /* NOTE: we are not taking an additional reference for init_net >since >> * we don't have to worry about it going away */ >> @@ -859,19 +867,15 @@ static void kauditd_send_multicast_skb(struct >sk_buff *skb) >> >> /* >> * The seemingly wasteful skb_copy() rather than bumping the >refcount >> - * using skb_get() is necessary because non-standard mods are >made to >> - * the skb by the original kaudit unicast socket send routine. >The >> - * existing auditd daemon assumes this breakage. Fixing this >would >> - * require co-ordinating a change in the established protocol >between >> - * the kaudit kernel subsystem and the auditd userspace code. >There is >> - * no reason for new multicast clients to continue with this >> - * non-compliance. >> + * using skb_get() is necessary because the unicast send in >> + * kauditd_send_queue() rewrites nlmsg_len to the payload only >length >> + * that auditd expects. The copy shields the multicast >listeners from >> + * that historical breakage, there is no reason for them to >continue >> + * with this non compliance. >> */ >> copy = skb_copy(skb, GFP_KERNEL); >> if (!copy) >> return; >> - nlh = nlmsg_hdr(copy); >> - nlh->nlmsg_len = skb->len; >> >> nlmsg_multicast(sock, copy, 0, AUDIT_NLGRP_READLOG, GFP_KERNEL); >> } >> @@ -2785,13 +2789,15 @@ int audit_signal_info(int sig, struct >task_struct *t) >> */ >> 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; >> + /* >> + * The record was built by appending data after >nlmsg_put() >> + * without keeping nlmsg_len up to date, so finalize the >> + * header here with the standard full message length. >The >> + * payload only length that auditd expects is applied at >> + * send time in kauditd_send_queue(). >> + */ >> + nlmsg_end(skb, nlmsg_hdr(skb)); >> >> /* queue the netlink packet */ >> skb_queue_tail(&audit_queue, skb); >> -- >> 2.47.3 >> >> >> >> >> >> >> >> Well, why not, please add: >> >> >> >> Reviewed-by: Bradley Morgan <[email protected]> >> >> Thanks! >> >> >> > >> >-Ricardo >> > >> > >> >> Thanks! >> > >It looks good to me. I've built a kernel to test it and verified that >it passes the audit testsuite. > ># uname -r >7.2.0-rc6+ > ># make test >make -C tests test >chmod +x */test >Running as user root > with context unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 > on system Fedora > >amcast_joinpart/test ................. ok >backlog_wait_time_actual_reset/test .. ok >bpf/test ............................. ok >coredump/test ........................ ok >exec_execve/test ..................... ok >exec_name/test ....................... ok >fanotify/test ........................ ok >field_compare/test ................... ok >file_create/test ..................... ok >file_delete/test ..................... ok >file_permission/test ................. ok >file_rename/test ..................... ok >filter_device/test ................... ok >filter_exclude/test .................. ok >filter_exit/test ..................... ok >filter_inode/test .................... ok >filter_saddr_fam/test ................ ok >filter_sessionid/test ................ ok >io_uring/test ........................ ok >login_tty/test ....................... ok >lost_reset/test ...................... ok >netfilter_pkt/test ................... ok >signal/test .......................... ok >syscalls_file/test ................... ok >syscall_module/test .................. ok >syscall_socketcall/test .............. ok >time_change/test ..................... ok >user_msg/test ........................ ok >All tests successful. >Files=28, Tests=303, 46 wallclock secs ( 0.08 usr 0.03 sys + 14.50 >cusr 1.56 csys = 16.17 CPU) >Result: PASS > >Reviewed-by: Ricardo Robaina <[email protected]> >Tested-by: Ricardo Robaina <[email protected]> > >-Ricardo > >
woah, thanks for the review too. so do I like post or will Paul take it Thanks!

