diff options
| author | David Miller <davem@davemloft.net> | 2015-04-05 22:19:04 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-04-07 15:25:55 -0400 |
| commit | 7026b1ddb6b8d4e6ee33dc2bd06c0ca8746fa7ab (patch) | |
| tree | 3e11ed0f186ea6066a3f7efecb88d85bc732ee51 /net/bridge | |
| parent | 1c984f8a5df085bcf35364a8a870bd4db4da4ed3 (diff) | |
netfilter: Pass socket pointer down through okfn().
On the output paths in particular, we have to sometimes deal with two
socket contexts. First, and usually skb->sk, is the local socket that
generated the frame.
And second, is potentially the socket used to control a tunneling
socket, such as one the encapsulates using UDP.
We do not want to disassociate skb->sk when encapsulating in order
to fix this, because that would break socket memory accounting.
The most extreme case where this can cause huge problems is an
AF_PACKET socket transmitting over a vxlan device. We hit code
paths doing checks that assume they are dealing with an ipv4
socket, but are actually operating upon the AF_PACKET one.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge')
| -rw-r--r-- | net/bridge/br_forward.c | 13 | ||||
| -rw-r--r-- | net/bridge/br_input.c | 16 | ||||
| -rw-r--r-- | net/bridge/br_multicast.c | 3 | ||||
| -rw-r--r-- | net/bridge/br_netfilter.c | 56 | ||||
| -rw-r--r-- | net/bridge/br_private.h | 6 | ||||
| -rw-r--r-- | net/bridge/br_stp_bpdu.c | 5 |
6 files changed, 56 insertions, 43 deletions
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 3304a5442331..e97572b5d2cc 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
| @@ -35,7 +35,7 @@ static inline int should_deliver(const struct net_bridge_port *p, | |||
| 35 | p->state == BR_STATE_FORWARDING; | 35 | p->state == BR_STATE_FORWARDING; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | int br_dev_queue_push_xmit(struct sk_buff *skb) | 38 | int br_dev_queue_push_xmit(struct sock *sk, struct sk_buff *skb) |
| 39 | { | 39 | { |
| 40 | if (!is_skb_forwardable(skb->dev, skb)) { | 40 | if (!is_skb_forwardable(skb->dev, skb)) { |
| 41 | kfree_skb(skb); | 41 | kfree_skb(skb); |
| @@ -49,9 +49,10 @@ int br_dev_queue_push_xmit(struct sk_buff *skb) | |||
| 49 | } | 49 | } |
| 50 | EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit); | 50 | EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit); |
| 51 | 51 | ||
| 52 | int br_forward_finish(struct sk_buff *skb) | 52 | int br_forward_finish(struct sock *sk, struct sk_buff *skb) |
| 53 | { | 53 | { |
| 54 | return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, | 54 | return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, sk, skb, |
| 55 | NULL, skb->dev, | ||
| 55 | br_dev_queue_push_xmit); | 56 | br_dev_queue_push_xmit); |
| 56 | 57 | ||
| 57 | } | 58 | } |
| @@ -75,7 +76,8 @@ static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) | |||
| 75 | return; | 76 | return; |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 78 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, | 79 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, |
| 80 | NULL, skb->dev, | ||
| 79 | br_forward_finish); | 81 | br_forward_finish); |
| 80 | } | 82 | } |
| 81 | 83 | ||
| @@ -96,7 +98,8 @@ static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb) | |||
| 96 | skb->dev = to->dev; | 98 | skb->dev = to->dev; |
| 97 | skb_forward_csum(skb); | 99 | skb_forward_csum(skb); |
| 98 | 100 | ||
| 99 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, | 101 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, NULL, skb, |
| 102 | indev, skb->dev, | ||
| 100 | br_forward_finish); | 103 | br_forward_finish); |
| 101 | } | 104 | } |
| 102 | 105 | ||
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 052c5ebbc947..f921a5dce22d 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
| @@ -55,8 +55,9 @@ static int br_pass_frame_up(struct sk_buff *skb) | |||
| 55 | if (!skb) | 55 | if (!skb) |
| 56 | return NET_RX_DROP; | 56 | return NET_RX_DROP; |
| 57 | 57 | ||
| 58 | return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, | 58 | return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb, |
| 59 | netif_receive_skb); | 59 | indev, NULL, |
| 60 | netif_receive_skb_sk); | ||
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br, | 63 | static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br, |
| @@ -119,7 +120,7 @@ static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br, | |||
| 119 | } | 120 | } |
| 120 | 121 | ||
| 121 | /* note: already called with rcu_read_lock */ | 122 | /* note: already called with rcu_read_lock */ |
| 122 | int br_handle_frame_finish(struct sk_buff *skb) | 123 | int br_handle_frame_finish(struct sock *sk, struct sk_buff *skb) |
| 123 | { | 124 | { |
| 124 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 125 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
| 125 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); | 126 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
| @@ -207,7 +208,7 @@ drop: | |||
| 207 | EXPORT_SYMBOL_GPL(br_handle_frame_finish); | 208 | EXPORT_SYMBOL_GPL(br_handle_frame_finish); |
| 208 | 209 | ||
| 209 | /* note: already called with rcu_read_lock */ | 210 | /* note: already called with rcu_read_lock */ |
| 210 | static int br_handle_local_finish(struct sk_buff *skb) | 211 | static int br_handle_local_finish(struct sock *sk, struct sk_buff *skb) |
| 211 | { | 212 | { |
| 212 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); | 213 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
| 213 | u16 vid = 0; | 214 | u16 vid = 0; |
| @@ -277,8 +278,8 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) | |||
| 277 | } | 278 | } |
| 278 | 279 | ||
| 279 | /* Deliver packet to local host only */ | 280 | /* Deliver packet to local host only */ |
| 280 | if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, | 281 | if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb, |
| 281 | NULL, br_handle_local_finish)) { | 282 | skb->dev, NULL, br_handle_local_finish)) { |
| 282 | return RX_HANDLER_CONSUMED; /* consumed by filter */ | 283 | return RX_HANDLER_CONSUMED; /* consumed by filter */ |
| 283 | } else { | 284 | } else { |
| 284 | *pskb = skb; | 285 | *pskb = skb; |
| @@ -302,7 +303,8 @@ forward: | |||
| 302 | if (ether_addr_equal(p->br->dev->dev_addr, dest)) | 303 | if (ether_addr_equal(p->br->dev->dev_addr, dest)) |
| 303 | skb->pkt_type = PACKET_HOST; | 304 | skb->pkt_type = PACKET_HOST; |
| 304 | 305 | ||
| 305 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, | 306 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, |
| 307 | skb->dev, NULL, | ||
| 306 | br_handle_frame_finish); | 308 | br_handle_frame_finish); |
| 307 | break; | 309 | break; |
| 308 | default: | 310 | default: |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index c465876c7861..4b6722f8f179 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
| @@ -814,7 +814,8 @@ static void __br_multicast_send_query(struct net_bridge *br, | |||
| 814 | 814 | ||
| 815 | if (port) { | 815 | if (port) { |
| 816 | skb->dev = port->dev; | 816 | skb->dev = port->dev; |
| 817 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, | 817 | NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, |
| 818 | NULL, skb->dev, | ||
| 818 | br_dev_queue_push_xmit); | 819 | br_dev_queue_push_xmit); |
| 819 | } else { | 820 | } else { |
| 820 | br_multicast_select_own_querier(br, ip, skb); | 821 | br_multicast_select_own_querier(br, ip, skb); |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 7527e94dd5dc..acd31c9f2116 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
| @@ -261,7 +261,7 @@ static void nf_bridge_update_protocol(struct sk_buff *skb) | |||
| 261 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ | 261 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ |
| 262 | /* Undo the changes made for ip6tables PREROUTING and continue the | 262 | /* Undo the changes made for ip6tables PREROUTING and continue the |
| 263 | * bridge PRE_ROUTING hook. */ | 263 | * bridge PRE_ROUTING hook. */ |
| 264 | static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) | 264 | static int br_nf_pre_routing_finish_ipv6(struct sock *sk, struct sk_buff *skb) |
| 265 | { | 265 | { |
| 266 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; | 266 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; |
| 267 | struct rtable *rt; | 267 | struct rtable *rt; |
| @@ -282,7 +282,8 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) | |||
| 282 | skb->dev = nf_bridge->physindev; | 282 | skb->dev = nf_bridge->physindev; |
| 283 | nf_bridge_update_protocol(skb); | 283 | nf_bridge_update_protocol(skb); |
| 284 | nf_bridge_push_encap_header(skb); | 284 | nf_bridge_push_encap_header(skb); |
| 285 | NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, | 285 | NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, sk, skb, |
| 286 | skb->dev, NULL, | ||
| 286 | br_handle_frame_finish, 1); | 287 | br_handle_frame_finish, 1); |
| 287 | 288 | ||
| 288 | return 0; | 289 | return 0; |
| @@ -293,7 +294,7 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) | |||
| 293 | * don't, we use the neighbour framework to find out. In both cases, we make | 294 | * don't, we use the neighbour framework to find out. In both cases, we make |
| 294 | * sure that br_handle_frame_finish() is called afterwards. | 295 | * sure that br_handle_frame_finish() is called afterwards. |
| 295 | */ | 296 | */ |
| 296 | static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) | 297 | static int br_nf_pre_routing_finish_bridge(struct sock *sk, struct sk_buff *skb) |
| 297 | { | 298 | { |
| 298 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; | 299 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; |
| 299 | struct neighbour *neigh; | 300 | struct neighbour *neigh; |
| @@ -310,7 +311,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) | |||
| 310 | if (neigh->hh.hh_len) { | 311 | if (neigh->hh.hh_len) { |
| 311 | neigh_hh_bridge(&neigh->hh, skb); | 312 | neigh_hh_bridge(&neigh->hh, skb); |
| 312 | skb->dev = nf_bridge->physindev; | 313 | skb->dev = nf_bridge->physindev; |
| 313 | ret = br_handle_frame_finish(skb); | 314 | ret = br_handle_frame_finish(sk, skb); |
| 314 | } else { | 315 | } else { |
| 315 | /* the neighbour function below overwrites the complete | 316 | /* the neighbour function below overwrites the complete |
| 316 | * MAC header, so we save the Ethernet source address and | 317 | * MAC header, so we save the Ethernet source address and |
| @@ -387,7 +388,7 @@ static bool dnat_took_place(const struct sk_buff *skb) | |||
| 387 | * device, we proceed as if ip_route_input() succeeded. If it differs from the | 388 | * device, we proceed as if ip_route_input() succeeded. If it differs from the |
| 388 | * logical bridge port or if ip_route_output_ | ||
