Skip to content

Commit e4485c7

Browse files
committed
Merge branch 'tcp-cb-selinux-corruption'
Eric Dumazet says: ==================== tcp: add tcp_v4_fill_cb()/tcp_v4_restore_cb() James Morris reported kernel stack corruption bug that we tracked back to commit 971f10e ("tcp: better TCP_SKB_CB layout to reduce cache line misses") First patch needs to be backported to kernels >= 3.18, while second patch needs to be backported to kernels >= 4.9, since this was the time when inet_exact_dif_match appeared. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents bcd1d60 + b4d1605 commit e4485c7

File tree

3 files changed

+47
-25
lines changed

3 files changed

+47
-25
lines changed

include/net/tcp.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,12 +844,11 @@ static inline int tcp_v6_sdif(const struct sk_buff *skb)
844844
}
845845
#endif
846846

847-
/* TCP_SKB_CB reference means this can not be used from early demux */
848847
static inline bool inet_exact_dif_match(struct net *net, struct sk_buff *skb)
849848
{
850849
#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
851850
if (!net->ipv4.sysctl_tcp_l3mdev_accept &&
852-
skb && ipv4_l3mdev_skb(TCP_SKB_CB(skb)->header.h4.flags))
851+
skb && ipv4_l3mdev_skb(IPCB(skb)->flags))
853852
return true;
854853
#endif
855854
return false;

net/ipv4/tcp_ipv4.c

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,34 @@ int tcp_filter(struct sock *sk, struct sk_buff *skb)
15911591
}
15921592
EXPORT_SYMBOL(tcp_filter);
15931593

1594+
static void tcp_v4_restore_cb(struct sk_buff *skb)
1595+
{
1596+
memmove(IPCB(skb), &TCP_SKB_CB(skb)->header.h4,
1597+
sizeof(struct inet_skb_parm));
1598+
}
1599+
1600+
static void tcp_v4_fill_cb(struct sk_buff *skb, const struct iphdr *iph,
1601+
const struct tcphdr *th)
1602+
{
1603+
/* This is tricky : We move IPCB at its correct location into TCP_SKB_CB()
1604+
* barrier() makes sure compiler wont play fool^Waliasing games.
1605+
*/
1606+
memmove(&TCP_SKB_CB(skb)->header.h4, IPCB(skb),
1607+
sizeof(struct inet_skb_parm));
1608+
barrier();
1609+
1610+
TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1611+
TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1612+
skb->len - th->doff * 4);
1613+
TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1614+
TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th);
1615+
TCP_SKB_CB(skb)->tcp_tw_isn = 0;
1616+
TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);
1617+
TCP_SKB_CB(skb)->sacked = 0;
1618+
TCP_SKB_CB(skb)->has_rxtstamp =
1619+
skb->tstamp || skb_hwtstamps(skb)->hwtstamp;
1620+
}
1621+
15941622
/*
15951623
* From tcp_input.c
15961624
*/
@@ -1631,24 +1659,6 @@ int tcp_v4_rcv(struct sk_buff *skb)
16311659

16321660
th = (const struct tcphdr *)skb->data;
16331661
iph = ip_hdr(skb);
1634-
/* This is tricky : We move IPCB at its correct location into TCP_SKB_CB()
1635-
* barrier() makes sure compiler wont play fool^Waliasing games.
1636-
*/
1637-
memmove(&TCP_SKB_CB(skb)->header.h4, IPCB(skb),
1638-
sizeof(struct inet_skb_parm));
1639-
barrier();
1640-
1641-
TCP_SKB_CB(skb)->seq = ntohl(th->seq);
1642-
TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
1643-
skb->len - th->doff * 4);
1644-
TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
1645-
TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th);
1646-
TCP_SKB_CB(skb)->tcp_tw_isn = 0;
1647-
TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);
1648-
TCP_SKB_CB(skb)->sacked = 0;
1649-
TCP_SKB_CB(skb)->has_rxtstamp =
1650-
skb->tstamp || skb_hwtstamps(skb)->hwtstamp;
1651-
16521662
lookup:
16531663
sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source,
16541664
th->dest, sdif, &refcounted);
@@ -1679,14 +1689,19 @@ int tcp_v4_rcv(struct sk_buff *skb)
16791689
sock_hold(sk);
16801690
refcounted = true;
16811691
nsk = NULL;
1682-
if (!tcp_filter(sk, skb))
1692+
if (!tcp_filter(sk, skb)) {
1693+
th = (const struct tcphdr *)skb->data;
1694+
iph = ip_hdr(skb);
1695+
tcp_v4_fill_cb(skb, iph, th);
16831696
nsk = tcp_check_req(sk, skb, req, false);
1697+
}
16841698
if (!nsk) {
16851699
reqsk_put(req);
16861700
goto discard_and_relse;
16871701
}
16881702
if (nsk == sk) {
16891703
reqsk_put(req);
1704+
tcp_v4_restore_cb(skb);
16901705
} else if (tcp_child_process(sk, nsk, skb)) {
16911706
tcp_v4_send_reset(nsk, skb);
16921707
goto discard_and_relse;
@@ -1712,6 +1727,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
17121727
goto discard_and_relse;
17131728
th = (const struct tcphdr *)skb->data;
17141729
iph = ip_hdr(skb);
1730+
tcp_v4_fill_cb(skb, iph, th);
17151731

17161732
skb->dev = NULL;
17171733

@@ -1742,6 +1758,8 @@ int tcp_v4_rcv(struct sk_buff *skb)
17421758
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
17431759
goto discard_it;
17441760

1761+
tcp_v4_fill_cb(skb, iph, th);
1762+
17451763
if (tcp_checksum_complete(skb)) {
17461764
csum_error:
17471765
__TCP_INC_STATS(net, TCP_MIB_CSUMERRORS);
@@ -1768,6 +1786,8 @@ int tcp_v4_rcv(struct sk_buff *skb)
17681786
goto discard_it;
17691787
}
17701788

1789+
tcp_v4_fill_cb(skb, iph, th);
1790+
17711791
if (tcp_checksum_complete(skb)) {
17721792
inet_twsk_put(inet_twsk(sk));
17731793
goto csum_error;
@@ -1784,6 +1804,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
17841804
if (sk2) {
17851805
inet_twsk_deschedule_put(inet_twsk(sk));
17861806
sk = sk2;
1807+
tcp_v4_restore_cb(skb);
17871808
refcounted = false;
17881809
goto process;
17891810
}

net/ipv6/tcp_ipv6.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,6 @@ static int tcp_v6_rcv(struct sk_buff *skb)
14541454
struct sock *nsk;
14551455

14561456
sk = req->rsk_listener;
1457-
tcp_v6_fill_cb(skb, hdr, th);
14581457
if (tcp_v6_inbound_md5_hash(sk, skb)) {
14591458
sk_drops_add(sk, skb);
14601459
reqsk_put(req);
@@ -1467,8 +1466,12 @@ static int tcp_v6_rcv(struct sk_buff *skb)
14671466
sock_hold(sk);
14681467
refcounted = true;
14691468
nsk = NULL;
1470-
if (!tcp_filter(sk, skb))
1469+
if (!tcp_filter(sk, skb)) {
1470+
th = (const struct tcphdr *)skb->data;
1471+
hdr = ipv6_hdr(skb);
1472+
tcp_v6_fill_cb(skb, hdr, th);
14711473
nsk = tcp_check_req(sk, skb, req, false);
1474+
}
14721475
if (!nsk) {
14731476
reqsk_put(req);
14741477
goto discard_and_relse;
@@ -1492,15 +1495,14 @@ static int tcp_v6_rcv(struct sk_buff *skb)
14921495
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
14931496
goto discard_and_relse;
14941497

1495-
tcp_v6_fill_cb(skb, hdr, th);
1496-
14971498
if (tcp_v6_inbound_md5_hash(sk, skb))
14981499
goto discard_and_relse;
14991500

15001501
if (tcp_filter(sk, skb))
15011502
goto discard_and_relse;
15021503
th = (const struct tcphdr *)skb->data;
15031504
hdr = ipv6_hdr(skb);
1505+
tcp_v6_fill_cb(skb, hdr, th);
15041506

15051507
skb->dev = NULL;
15061508

0 commit comments

Comments
 (0)