On 11/30/2017 2:50 AM, Eric Dumazet wrote: > On Wed, 2017-11-29 at 19:16 -0800, Casey Schaufler wrote: >> On 11/29/2017 4:31 PM, James Morris wrote: >>> On Wed, 29 Nov 2017, Casey Schaufler wrote: >>> >>>> I see that there is a proposed fix later in the thread, but I >>>> don't see >>>> the patch. Could you send it to me, so I can try it on my >>>> problem? >>> Forwarded off-list. >> The patch does fix the problem I was seeing in Smack. > Can you guys test the following more complete patch ? My tests are passing. Thank you. Tested-by: Casey Schaufler <casey@xxxxxxxxxxxxxxxx> > > It should cover IPv4 and IPv6, and also the corner cases. > > ( Note that I squashed ipv6 fix in https://patchwork.ozlabs.org/patch/8 > 42844/ that I spotted while cooking this patch ) > > diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c > index c6bc0c4d19c624888b0d0b5a4246c7183edf63f5..77ea45da0fe9c746907a312989658af3ad3b198d 100644 > --- a/net/ipv4/tcp_ipv4.c > +++ b/net/ipv4/tcp_ipv4.c > @@ -1591,6 +1591,34 @@ int tcp_filter(struct sock *sk, struct sk_buff *skb) > } > EXPORT_SYMBOL(tcp_filter); > > +static void tcp_v4_restore_cb(struct sk_buff *skb) > +{ > + memmove(IPCB(skb), &TCP_SKB_CB(skb)->header.h4, > + sizeof(struct inet_skb_parm)); > +} > + > +static void tcp_v4_fill_cb(struct sk_buff *skb, const struct iphdr *iph, > + const struct tcphdr *th) > +{ > + /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() > + * barrier() makes sure compiler wont play fool^Waliasing games. > + */ > + memmove(&TCP_SKB_CB(skb)->header.h4, IPCB(skb), > + sizeof(struct inet_skb_parm)); > + barrier(); > + > + TCP_SKB_CB(skb)->seq = ntohl(th->seq); > + TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + > + skb->len - th->doff * 4); > + TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); > + TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); > + TCP_SKB_CB(skb)->tcp_tw_isn = 0; > + TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); > + TCP_SKB_CB(skb)->sacked = 0; > + TCP_SKB_CB(skb)->has_rxtstamp = > + skb->tstamp || skb_hwtstamps(skb)->hwtstamp; > +} > + > /* > * From tcp_input.c > */ > @@ -1631,24 +1659,6 @@ int tcp_v4_rcv(struct sk_buff *skb) > > th = (const struct tcphdr *)skb->data; > iph = ip_hdr(skb); > - /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() > - * barrier() makes sure compiler wont play fool^Waliasing games. > - */ > - memmove(&TCP_SKB_CB(skb)->header.h4, IPCB(skb), > - sizeof(struct inet_skb_parm)); > - barrier(); > - > - TCP_SKB_CB(skb)->seq = ntohl(th->seq); > - TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + > - skb->len - th->doff * 4); > - TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); > - TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); > - TCP_SKB_CB(skb)->tcp_tw_isn = 0; > - TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); > - TCP_SKB_CB(skb)->sacked = 0; > - TCP_SKB_CB(skb)->has_rxtstamp = > - skb->tstamp || skb_hwtstamps(skb)->hwtstamp; > - > lookup: > sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source, > th->dest, sdif, &refcounted); > @@ -1679,14 +1689,19 @@ int tcp_v4_rcv(struct sk_buff *skb) > sock_hold(sk); > refcounted = true; > nsk = NULL; > - if (!tcp_filter(sk, skb)) > + if (!tcp_filter(sk, skb)) { > + th = (const struct tcphdr *)skb->data; > + iph = ip_hdr(skb); > + tcp_v4_fill_cb(skb, iph, th); > nsk = tcp_check_req(sk, skb, req, false); > + } > if (!nsk) { > reqsk_put(req); > goto discard_and_relse; > } > if (nsk == sk) { > reqsk_put(req); > + tcp_v4_restore_cb(skb); > } else if (tcp_child_process(sk, nsk, skb)) { > tcp_v4_send_reset(nsk, skb); > goto discard_and_relse; > @@ -1712,6 +1727,7 @@ int tcp_v4_rcv(struct sk_buff *skb) > goto discard_and_relse; > th = (const struct tcphdr *)skb->data; > iph = ip_hdr(skb); > + tcp_v4_fill_cb(skb, iph, th); > > skb->dev = NULL; > > @@ -1742,6 +1758,8 @@ int tcp_v4_rcv(struct sk_buff *skb) > if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) > goto discard_it; > > + tcp_v4_fill_cb(skb, iph, th); > + > if (tcp_checksum_complete(skb)) { > csum_error: > __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); > @@ -1768,6 +1786,8 @@ int tcp_v4_rcv(struct sk_buff *skb) > goto discard_it; > } > > + tcp_v4_fill_cb(skb, iph, th); > + > if (tcp_checksum_complete(skb)) { > inet_twsk_put(inet_twsk(sk)); > goto csum_error; > @@ -1784,6 +1804,7 @@ int tcp_v4_rcv(struct sk_buff *skb) > if (sk2) { > inet_twsk_deschedule_put(inet_twsk(sk)); > sk = sk2; > + tcp_v4_restore_cb(skb); > refcounted = false; > goto process; > } > diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c > index 6bb98c93edfe2ed2f16fe5229605f8108cfc7f9a..1f04ec0e4a7aa2c11b8ee27cbdd4067b5bcf32e5 100644 > --- a/net/ipv6/tcp_ipv6.c > +++ b/net/ipv6/tcp_ipv6.c > @@ -1454,7 +1454,6 @@ static int tcp_v6_rcv(struct sk_buff *skb) > struct sock *nsk; > > sk = req->rsk_listener; > - tcp_v6_fill_cb(skb, hdr, th); > if (tcp_v6_inbound_md5_hash(sk, skb)) { > sk_drops_add(sk, skb); > reqsk_put(req); > @@ -1467,8 +1466,12 @@ static int tcp_v6_rcv(struct sk_buff *skb) > sock_hold(sk); > refcounted = true; > nsk = NULL; > - if (!tcp_filter(sk, skb)) > + if (!tcp_filter(sk, skb)) { > + th = (const struct tcphdr *)skb->data; > + hdr = ipv6_hdr(skb); > + tcp_v6_fill_cb(skb, hdr, th); > nsk = tcp_check_req(sk, skb, req, false); > + } > if (!nsk) { > reqsk_put(req); > goto discard_and_relse; > @@ -1492,8 +1495,6 @@ static int tcp_v6_rcv(struct sk_buff *skb) > if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) > goto discard_and_relse; > > - tcp_v6_fill_cb(skb, hdr, th); > - > if (tcp_v6_inbound_md5_hash(sk, skb)) > goto discard_and_relse; > > @@ -1501,6 +1502,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) > goto discard_and_relse; > th = (const struct tcphdr *)skb->data; > hdr = ipv6_hdr(skb); > + tcp_v6_fill_cb(skb, hdr, th); > > skb->dev = NULL; > > @@ -1590,7 +1592,6 @@ static int tcp_v6_rcv(struct sk_buff *skb) > tcp_v6_timewait_ack(sk, skb); > break; > case TCP_TW_RST: > - tcp_v6_restore_cb(skb); > tcp_v6_send_reset(sk, skb); > inet_twsk_deschedule_put(inet_twsk(sk)); > goto discard_it; > > > >