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 971f10eca186 ("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 <davem@davemloft.net>
This commit is contained in:
commit
e4485c7484
@ -844,12 +844,11 @@ static inline int tcp_v6_sdif(const struct sk_buff *skb)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* TCP_SKB_CB reference means this can not be used from early demux */
|
|
||||||
static inline bool inet_exact_dif_match(struct net *net, struct sk_buff *skb)
|
static inline bool inet_exact_dif_match(struct net *net, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
|
#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
|
||||||
if (!net->ipv4.sysctl_tcp_l3mdev_accept &&
|
if (!net->ipv4.sysctl_tcp_l3mdev_accept &&
|
||||||
skb && ipv4_l3mdev_skb(TCP_SKB_CB(skb)->header.h4.flags))
|
skb && ipv4_l3mdev_skb(IPCB(skb)->flags))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
return false;
|
return false;
|
||||||
|
@ -1591,6 +1591,34 @@ int tcp_filter(struct sock *sk, struct sk_buff *skb)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tcp_filter);
|
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
|
* From tcp_input.c
|
||||||
*/
|
*/
|
||||||
@ -1631,24 +1659,6 @@ int tcp_v4_rcv(struct sk_buff *skb)
|
|||||||
|
|
||||||
th = (const struct tcphdr *)skb->data;
|
th = (const struct tcphdr *)skb->data;
|
||||||
iph = ip_hdr(skb);
|
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:
|
lookup:
|
||||||
sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source,
|
sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source,
|
||||||
th->dest, sdif, &refcounted);
|
th->dest, sdif, &refcounted);
|
||||||
@ -1679,14 +1689,19 @@ process:
|
|||||||
sock_hold(sk);
|
sock_hold(sk);
|
||||||
refcounted = true;
|
refcounted = true;
|
||||||
nsk = NULL;
|
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);
|
nsk = tcp_check_req(sk, skb, req, false);
|
||||||
|
}
|
||||||
if (!nsk) {
|
if (!nsk) {
|
||||||
reqsk_put(req);
|
reqsk_put(req);
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
}
|
}
|
||||||
if (nsk == sk) {
|
if (nsk == sk) {
|
||||||
reqsk_put(req);
|
reqsk_put(req);
|
||||||
|
tcp_v4_restore_cb(skb);
|
||||||
} else if (tcp_child_process(sk, nsk, skb)) {
|
} else if (tcp_child_process(sk, nsk, skb)) {
|
||||||
tcp_v4_send_reset(nsk, skb);
|
tcp_v4_send_reset(nsk, skb);
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
@ -1712,6 +1727,7 @@ process:
|
|||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
th = (const struct tcphdr *)skb->data;
|
th = (const struct tcphdr *)skb->data;
|
||||||
iph = ip_hdr(skb);
|
iph = ip_hdr(skb);
|
||||||
|
tcp_v4_fill_cb(skb, iph, th);
|
||||||
|
|
||||||
skb->dev = NULL;
|
skb->dev = NULL;
|
||||||
|
|
||||||
@ -1742,6 +1758,8 @@ no_tcp_socket:
|
|||||||
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
|
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
|
||||||
goto discard_it;
|
goto discard_it;
|
||||||
|
|
||||||
|
tcp_v4_fill_cb(skb, iph, th);
|
||||||
|
|
||||||
if (tcp_checksum_complete(skb)) {
|
if (tcp_checksum_complete(skb)) {
|
||||||
csum_error:
|
csum_error:
|
||||||
__TCP_INC_STATS(net, TCP_MIB_CSUMERRORS);
|
__TCP_INC_STATS(net, TCP_MIB_CSUMERRORS);
|
||||||
@ -1768,6 +1786,8 @@ do_time_wait:
|
|||||||
goto discard_it;
|
goto discard_it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tcp_v4_fill_cb(skb, iph, th);
|
||||||
|
|
||||||
if (tcp_checksum_complete(skb)) {
|
if (tcp_checksum_complete(skb)) {
|
||||||
inet_twsk_put(inet_twsk(sk));
|
inet_twsk_put(inet_twsk(sk));
|
||||||
goto csum_error;
|
goto csum_error;
|
||||||
@ -1784,6 +1804,7 @@ do_time_wait:
|
|||||||
if (sk2) {
|
if (sk2) {
|
||||||
inet_twsk_deschedule_put(inet_twsk(sk));
|
inet_twsk_deschedule_put(inet_twsk(sk));
|
||||||
sk = sk2;
|
sk = sk2;
|
||||||
|
tcp_v4_restore_cb(skb);
|
||||||
refcounted = false;
|
refcounted = false;
|
||||||
goto process;
|
goto process;
|
||||||
}
|
}
|
||||||
|
@ -1454,7 +1454,6 @@ process:
|
|||||||
struct sock *nsk;
|
struct sock *nsk;
|
||||||
|
|
||||||
sk = req->rsk_listener;
|
sk = req->rsk_listener;
|
||||||
tcp_v6_fill_cb(skb, hdr, th);
|
|
||||||
if (tcp_v6_inbound_md5_hash(sk, skb)) {
|
if (tcp_v6_inbound_md5_hash(sk, skb)) {
|
||||||
sk_drops_add(sk, skb);
|
sk_drops_add(sk, skb);
|
||||||
reqsk_put(req);
|
reqsk_put(req);
|
||||||
@ -1467,8 +1466,12 @@ process:
|
|||||||
sock_hold(sk);
|
sock_hold(sk);
|
||||||
refcounted = true;
|
refcounted = true;
|
||||||
nsk = NULL;
|
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);
|
nsk = tcp_check_req(sk, skb, req, false);
|
||||||
|
}
|
||||||
if (!nsk) {
|
if (!nsk) {
|
||||||
reqsk_put(req);
|
reqsk_put(req);
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
@ -1492,8 +1495,6 @@ process:
|
|||||||
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
|
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
|
|
||||||
tcp_v6_fill_cb(skb, hdr, th);
|
|
||||||
|
|
||||||
if (tcp_v6_inbound_md5_hash(sk, skb))
|
if (tcp_v6_inbound_md5_hash(sk, skb))
|
||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
|
|
||||||
@ -1501,6 +1502,7 @@ process:
|
|||||||
goto discard_and_relse;
|
goto discard_and_relse;
|
||||||
th = (const struct tcphdr *)skb->data;
|
th = (const struct tcphdr *)skb->data;
|
||||||
hdr = ipv6_hdr(skb);
|
hdr = ipv6_hdr(skb);
|
||||||
|
tcp_v6_fill_cb(skb, hdr, th);
|
||||||
|
|
||||||
skb->dev = NULL;
|
skb->dev = NULL;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user