kernel: backport flow offload pppoe fix
[openwrt/staging/stintel.git] / target / linux / generic / backport-5.15 / 741-v6.9-01-netfilter-flowtable-validate-pppoe-header.patch
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Thu, 11 Apr 2024 13:28:59 +0200
3 Subject: [PATCH] netfilter: flowtable: validate pppoe header
4
5 Ensure there is sufficient room to access the protocol field of the
6 PPPoe header. Validate it once before the flowtable lookup, then use a
7 helper function to access protocol field.
8
9 Reported-by: syzbot+b6f07e1c07ef40199081@syzkaller.appspotmail.com
10 Fixes: 72efd585f714 ("netfilter: flowtable: add pppoe support")
11 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
12 ---
13
14 --- a/include/net/netfilter/nf_flow_table.h
15 +++ b/include/net/netfilter/nf_flow_table.h
16 @@ -318,7 +318,7 @@ int nf_flow_rule_route_ipv6(struct net *
17 int nf_flow_table_offload_init(void);
18 void nf_flow_table_offload_exit(void);
19
20 -static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb)
21 +static inline __be16 __nf_flow_pppoe_proto(const struct sk_buff *skb)
22 {
23 __be16 proto;
24
25 @@ -334,4 +334,14 @@ static inline __be16 nf_flow_pppoe_proto
26 return 0;
27 }
28
29 +static inline bool nf_flow_pppoe_proto(struct sk_buff *skb, __be16 *inner_proto)
30 +{
31 + if (!pskb_may_pull(skb, PPPOE_SES_HLEN))
32 + return false;
33 +
34 + *inner_proto = __nf_flow_pppoe_proto(skb);
35 +
36 + return true;
37 +}
38 +
39 #endif /* _NF_FLOW_TABLE_H */
40 --- a/net/netfilter/nf_flow_table_inet.c
41 +++ b/net/netfilter/nf_flow_table_inet.c
42 @@ -21,7 +21,8 @@ nf_flow_offload_inet_hook(void *priv, st
43 proto = veth->h_vlan_encapsulated_proto;
44 break;
45 case htons(ETH_P_PPP_SES):
46 - proto = nf_flow_pppoe_proto(skb);
47 + if (!nf_flow_pppoe_proto(skb, &proto))
48 + return NF_ACCEPT;
49 break;
50 default:
51 proto = skb->protocol;
52 --- a/net/netfilter/nf_flow_table_ip.c
53 +++ b/net/netfilter/nf_flow_table_ip.c
54 @@ -246,10 +246,11 @@ static unsigned int nf_flow_xmit_xfrm(st
55 return NF_STOLEN;
56 }
57
58 -static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto,
59 +static bool nf_flow_skb_encap_protocol(struct sk_buff *skb, __be16 proto,
60 u32 *offset)
61 {
62 struct vlan_ethhdr *veth;
63 + __be16 inner_proto;
64
65 switch (skb->protocol) {
66 case htons(ETH_P_8021Q):
67 @@ -260,7 +261,8 @@ static bool nf_flow_skb_encap_protocol(c
68 }
69 break;
70 case htons(ETH_P_PPP_SES):
71 - if (nf_flow_pppoe_proto(skb) == proto) {
72 + if (nf_flow_pppoe_proto(skb, &inner_proto) &&
73 + inner_proto == proto) {
74 *offset += PPPOE_SES_HLEN;
75 return true;
76 }
77 @@ -289,7 +291,7 @@ static void nf_flow_encap_pop(struct sk_
78 skb_reset_network_header(skb);
79 break;
80 case htons(ETH_P_PPP_SES):
81 - skb->protocol = nf_flow_pppoe_proto(skb);
82 + skb->protocol = __nf_flow_pppoe_proto(skb);
83 skb_pull(skb, PPPOE_SES_HLEN);
84 skb_reset_network_header(skb);
85 break;