]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.0/net-bridge-fix-per-port-af_packet-sockets.patch
5.0-stable patches
[thirdparty/kernel/stable-queue.git] / queue-5.0 / net-bridge-fix-per-port-af_packet-sockets.patch
1 From foo@baz Sat Apr 20 16:43:09 CEST 2019
2 From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
3 Date: Thu, 11 Apr 2019 13:56:39 +0300
4 Subject: net: bridge: fix per-port af_packet sockets
5
6 From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
7
8 [ Upstream commit 3b2e2904deb314cc77a2192f506f2fd44e3d10d0 ]
9
10 When the commit below was introduced it changed two visible things:
11 - the skb was no longer passed through the protocol handlers with the
12 original device
13 - the skb was passed up the stack with skb->dev = bridge
14
15 The first change broke af_packet sockets on bridge ports. For example we
16 use them for hostapd which listens for ETH_P_PAE packets on the ports.
17 We discussed two possible fixes:
18 - create a clone and pass it through NF_HOOK(), act on the original skb
19 based on the result
20 - somehow signal to the caller from the okfn() that it was called,
21 meaning the skb is ok to be passed, which this patch is trying to
22 implement via returning 1 from the bridge link-local okfn()
23
24 Note that we rely on the fact that NF_QUEUE/STOLEN would return 0 and
25 drop/error would return < 0 thus the okfn() is called only when the
26 return was 1, so we signal to the caller that it was called by preserving
27 the return value from nf_hook().
28
29 Fixes: 8626c56c8279 ("bridge: fix potential use-after-free when hook returns QUEUE or STOLEN verdict")
30 Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
31 Signed-off-by: David S. Miller <davem@davemloft.net>
32 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
33 ---
34 net/bridge/br_input.c | 23 ++++++++++++++---------
35 1 file changed, 14 insertions(+), 9 deletions(-)
36
37 --- a/net/bridge/br_input.c
38 +++ b/net/bridge/br_input.c
39 @@ -197,13 +197,10 @@ static void __br_handle_local_finish(str
40 /* note: already called with rcu_read_lock */
41 static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
42 {
43 - struct net_bridge_port *p = br_port_get_rcu(skb->dev);
44 -
45 __br_handle_local_finish(skb);
46
47 - BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
48 - br_pass_frame_up(skb);
49 - return 0;
50 + /* return 1 to signal the okfn() was called so it's ok to use the skb */
51 + return 1;
52 }
53
54 /*
55 @@ -280,10 +277,18 @@ rx_handler_result_t br_handle_frame(stru
56 goto forward;
57 }
58
59 - /* Deliver packet to local host only */
60 - NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, dev_net(skb->dev),
61 - NULL, skb, skb->dev, NULL, br_handle_local_finish);
62 - return RX_HANDLER_CONSUMED;
63 + /* The else clause should be hit when nf_hook():
64 + * - returns < 0 (drop/error)
65 + * - returns = 0 (stolen/nf_queue)
66 + * Thus return 1 from the okfn() to signal the skb is ok to pass
67 + */
68 + if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
69 + dev_net(skb->dev), NULL, skb, skb->dev, NULL,
70 + br_handle_local_finish) == 1) {
71 + return RX_HANDLER_PASS;
72 + } else {
73 + return RX_HANDLER_CONSUMED;
74 + }
75 }
76
77 forward: