From 38ca787ab46c107187a9fcfd08cf3e4907dcab61 Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Wed, 22 Jun 2022 16:31:50 +0200 Subject: [PATCH] pf: copy out rather than m_pullup() in pf_test_eth_rule() Don't change the mbuf chain layout. We've encountered alignment issues in the tcp syncookie code on armv7, which appear to result from the m_pullup() here. eg: Kernel page fault with the following non-sleepable locks held: exclusive sleep mutex tcp_sc_head (tcp_sc_head) r = 0 (0xdbfc4058) locked @ /usr/src/sys/netinet/tcp_syncache.c:534 exclusive rw tcpinp (tcpinp) r = 0 (0xded8ee28) locked @ /usr/src/sys/netinet/in_pcb.c:2436 stack backtrace: #0 0xc0421480 at witness_debugger+0x6c #1 0xc0422514 at witness_warn+0x430 #2 0xc07d8830 at abort_handler+0x1d8 #3 0xc07bb1cc at exception_exit+0 #4 0xc06320bc at syncookie_lookup+0x4c #5 0xc0630cb0 at syncache_expand+0xc4 #6 0xc061be00 at tcp_input+0x11b0 #7 0xc058f8b4 at ip_input+0x264 #8 0xc04f5ca8 at netisr_dispatch_src+0xec #9 0xc04d39e8 at ether_demux+0x204 #10 0xc04d5088 at ether_nh_input+0x3e8 #11 0xc04f5ca8 at netisr_dispatch_src+0xec #12 0xc04d3f10 at ether_input+0xfc #13 0xc07fa750 at mvneta_rxtxth_intr+0x2b4 #14 0xc037f784 at ithread_loop+0x1cc #15 0xc037c4c8 at fork_exit+0xa0 #16 0xc07bb15c at swi_exit+0 Fatal kernel mode data abort: 'Alignment Fault' on read trapframe: 0xc7d28980 FSR=00000001, FAR=dbf7886e, spsr=60000013 r0 =00000025, r1 =00000001, r2 =c7d2894c, r3 =60000013 r4 =c7d28a58, r5 =c7d28bc8, r6 =dbf7886a, r7 =dbfc4058 r8 =dbfc4058, r9 =c7d28b98, r10=c7d28bfc, r11=c7d28a30 r12=20000000, ssp=c7d28a10, slr=c06320bc, pc =c06320bc Redmine: 8287 --- sys/netpfil/pf/pf.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 0452ac215a7f1..002fb198d369d 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -3820,6 +3820,8 @@ pf_match_eth_addr(const uint8_t *a, const struct pf_keth_rule_addr *r) static int pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0) { + struct ip ip; + struct ip6_hdr ip6; struct mbuf *m = *m0; struct ether_header *e; struct pf_keth_rule *r, *rm, *a = NULL; @@ -3862,31 +3864,17 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0) switch (proto) { case ETHERTYPE_IP: { - struct ip *ip; - m = m_pullup(m, sizeof(struct ether_header) + - sizeof(struct ip)); - if (m == NULL) { - *m0 = NULL; - return (PF_DROP); - } + m_copydata(m, sizeof(struct ether_header), sizeof(ip), (caddr_t)&ip); af = AF_INET; - ip = mtodo(m, sizeof(struct ether_header)); - src = (struct pf_addr *)&ip->ip_src; - dst = (struct pf_addr *)&ip->ip_dst; + src = (struct pf_addr *)&ip.ip_src; + dst = (struct pf_addr *)&ip.ip_dst; break; } case ETHERTYPE_IPV6: { - struct ip6_hdr *ip6; - m = m_pullup(m, sizeof(struct ether_header) + - sizeof(struct ip6_hdr)); - if (m == NULL) { - *m0 = NULL; - return (PF_DROP); - } + m_copydata(m, sizeof(struct ether_header), sizeof(ip6), (caddr_t)&ip6); af = AF_INET6; - ip6 = mtodo(m, sizeof(struct ether_header)); - src = (struct pf_addr *)&ip6->ip6_src; - dst = (struct pf_addr *)&ip6->ip6_dst; + src = (struct pf_addr *)&ip6.ip6_src; + dst = (struct pf_addr *)&ip6.ip6_dst; break; } }