diff options
author | David S. Miller <davem@davemloft.net> | 2014-06-04 02:32:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-04 02:32:12 -0400 |
commit | c99f7abf0e69987e4add567e155e042cb1f2a20b (patch) | |
tree | d23898dc30ed25c1dae9bb6325041027d412397a /net | |
parent | 92ff71b8fe9cd9c673615fc6f3870af7376d7c84 (diff) | |
parent | d8b0426af5b67973585712c9af36b86f6ea97815 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts:
include/net/inetpeer.h
net/ipv6/output_core.c
Changes in net were fixing bugs in code removed in net-next.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/batman-adv/multicast.c | 6 | ||||
-rw-r--r-- | net/bridge/br_fdb.c | 8 | ||||
-rw-r--r-- | net/bridge/br_input.c | 4 | ||||
-rw-r--r-- | net/bridge/br_private.h | 7 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 28 | ||||
-rw-r--r-- | net/core/dev.c | 35 | ||||
-rw-r--r-- | net/core/filter.c | 7 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 10 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 11 | ||||
-rw-r--r-- | net/ipv6/output_core.c | 1 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 15 | ||||
-rw-r--r-- | net/netlink/af_netlink.c | 7 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 36 |
13 files changed, 131 insertions, 44 deletions
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 8c7ca811de6e..96b66fd30f96 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c | |||
@@ -415,7 +415,7 @@ batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv) | |||
415 | hlist_for_each_entry_rcu(tmp_orig_node, | 415 | hlist_for_each_entry_rcu(tmp_orig_node, |
416 | &bat_priv->mcast.want_all_ipv4_list, | 416 | &bat_priv->mcast.want_all_ipv4_list, |
417 | mcast_want_all_ipv4_node) { | 417 | mcast_want_all_ipv4_node) { |
418 | if (!atomic_inc_not_zero(&orig_node->refcount)) | 418 | if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) |
419 | continue; | 419 | continue; |
420 | 420 | ||
421 | orig_node = tmp_orig_node; | 421 | orig_node = tmp_orig_node; |
@@ -442,7 +442,7 @@ batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv) | |||
442 | hlist_for_each_entry_rcu(tmp_orig_node, | 442 | hlist_for_each_entry_rcu(tmp_orig_node, |
443 | &bat_priv->mcast.want_all_ipv6_list, | 443 | &bat_priv->mcast.want_all_ipv6_list, |
444 | mcast_want_all_ipv6_node) { | 444 | mcast_want_all_ipv6_node) { |
445 | if (!atomic_inc_not_zero(&orig_node->refcount)) | 445 | if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) |
446 | continue; | 446 | continue; |
447 | 447 | ||
448 | orig_node = tmp_orig_node; | 448 | orig_node = tmp_orig_node; |
@@ -493,7 +493,7 @@ batadv_mcast_forw_unsnoop_node_get(struct batadv_priv *bat_priv) | |||
493 | hlist_for_each_entry_rcu(tmp_orig_node, | 493 | hlist_for_each_entry_rcu(tmp_orig_node, |
494 | &bat_priv->mcast.want_all_unsnoopables_list, | 494 | &bat_priv->mcast.want_all_unsnoopables_list, |
495 | mcast_want_all_unsnoopables_node) { | 495 | mcast_want_all_unsnoopables_node) { |
496 | if (!atomic_inc_not_zero(&orig_node->refcount)) | 496 | if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) |
497 | continue; | 497 | continue; |
498 | 498 | ||
499 | orig_node = tmp_orig_node; | 499 | orig_node = tmp_orig_node; |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 2c45c069ea1a..b524c36c1273 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -538,6 +538,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, | |||
538 | { | 538 | { |
539 | struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)]; | 539 | struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)]; |
540 | struct net_bridge_fdb_entry *fdb; | 540 | struct net_bridge_fdb_entry *fdb; |
541 | bool fdb_modified = false; | ||
541 | 542 | ||
542 | /* some users want to always flood. */ | 543 | /* some users want to always flood. */ |
543 | if (hold_time(br) == 0) | 544 | if (hold_time(br) == 0) |
@@ -558,10 +559,15 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, | |||
558 | source->dev->name); | 559 | source->dev->name); |
559 | } else { | 560 | } else { |
560 | /* fastpath: update of existing entry */ | 561 | /* fastpath: update of existing entry */ |
561 | fdb->dst = source; | 562 | if (unlikely(source != fdb->dst)) { |
563 | fdb->dst = source; | ||
564 | fdb_modified = true; | ||
565 | } | ||
562 | fdb->updated = jiffies; | 566 | fdb->updated = jiffies; |
563 | if (unlikely(added_by_user)) | 567 | if (unlikely(added_by_user)) |
564 | fdb->added_by_user = 1; | 568 | fdb->added_by_user = 1; |
569 | if (unlikely(fdb_modified)) | ||
570 | fdb_notify(br, fdb, RTM_NEWNEIGH); | ||
565 | } | 571 | } |
566 | } else { | 572 | } else { |
567 | spin_lock(&br->hash_lock); | 573 | spin_lock(&br->hash_lock); |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 7985deaff52f..04d6348fd530 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -147,8 +147,8 @@ static int br_handle_local_finish(struct sk_buff *skb) | |||
147 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); | 147 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
148 | u16 vid = 0; | 148 | u16 vid = 0; |
149 | 149 | ||
150 | br_vlan_get_tag(skb, &vid); | 150 | /* check if vlan is allowed, to avoid spoofing */ |
151 | if (p->flags & BR_LEARNING) | 151 | if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid)) |
152 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false); | 152 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false); |
153 | return 0; /* process further */ | 153 | return 0; /* process further */ |
154 | } | 154 | } |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 53d6e32965fc..bc17210d4c52 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -589,6 +589,7 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, | |||
589 | struct sk_buff *skb, u16 *vid); | 589 | struct sk_buff *skb, u16 *vid); |
590 | bool br_allowed_egress(struct net_bridge *br, const struct net_port_vlans *v, | 590 | bool br_allowed_egress(struct net_bridge *br, const struct net_port_vlans *v, |
591 | const struct sk_buff *skb); | 591 | const struct sk_buff *skb); |
592 | bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid); | ||
592 | struct sk_buff *br_handle_vlan(struct net_bridge *br, | 593 | struct sk_buff *br_handle_vlan(struct net_bridge *br, |
593 | const struct net_port_vlans *v, | 594 | const struct net_port_vlans *v, |
594 | struct sk_buff *skb); | 595 | struct sk_buff *skb); |
@@ -660,6 +661,12 @@ static inline bool br_allowed_egress(struct net_bridge *br, | |||
660 | return true; | 661 | return true; |
661 | } | 662 | } |
662 | 663 | ||
664 | static inline bool br_should_learn(struct net_bridge_port *p, | ||
665 | struct sk_buff *skb, u16 *vid) | ||
666 | { | ||
667 | return true; | ||
668 | } | ||
669 | |||
663 | static inline struct sk_buff *br_handle_vlan(struct net_bridge *br, | 670 | static inline struct sk_buff *br_handle_vlan(struct net_bridge *br, |
664 | const struct net_port_vlans *v, | 671 | const struct net_port_vlans *v, |
665 | struct sk_buff *skb) | 672 | struct sk_buff *skb) |
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 24c5cc55589f..fcc95390f862 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c | |||
@@ -241,6 +241,34 @@ bool br_allowed_egress(struct net_bridge *br, | |||
241 | return false; | 241 | return false; |
242 | } | 242 | } |
243 | 243 | ||
244 | /* Called under RCU */ | ||
245 | bool br_should_learn(struct net_bridge_port *p, struct sk_buff *skb, u16 *vid) | ||
246 | { | ||
247 | struct net_bridge *br = p->br; | ||
248 | struct net_port_vlans *v; | ||
249 | |||
250 | if (!br->vlan_enabled) | ||
251 | return true; | ||
252 | |||
253 | v = rcu_dereference(p->vlan_info); | ||
254 | if (!v) | ||
255 | return false; | ||
256 | |||
257 | br_vlan_get_tag(skb, vid); | ||
258 | if (!*vid) { | ||
259 | *vid = br_get_pvid(v); | ||
260 | if (*vid == VLAN_N_VID) | ||
261 | return false; | ||
262 | |||
263 | return true; | ||
264 | } | ||
265 | |||
266 | if (test_bit(*vid, v->vlan_bitmap)) | ||
267 | return true; | ||
268 | |||
269 | return false; | ||
270 | } | ||
271 | |||
244 | /* Must be protected by RTNL. | 272 | /* Must be protected by RTNL. |
245 | * Must be called with vid in range from 1 to 4094 inclusive. | 273 | * Must be called with vid in range from 1 to 4094 inclusive. |
246 | */ | 274 | */ |
diff --git a/net/core/dev.c b/net/core/dev.c index 1ba2cfe3f8e8..5367bfba0947 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2289,8 +2289,8 @@ EXPORT_SYMBOL(skb_checksum_help); | |||
2289 | 2289 | ||
2290 | __be16 skb_network_protocol(struct sk_buff *skb, int *depth) | 2290 | __be16 skb_network_protocol(struct sk_buff *skb, int *depth) |
2291 | { | 2291 | { |
2292 | unsigned int vlan_depth = skb->mac_len; | ||
2292 | __be16 type = skb->protocol; | 2293 | __be16 type = skb->protocol; |
2293 | int vlan_depth = skb->mac_len; | ||
2294 | 2294 | ||
2295 | /* Tunnel gso handlers can set protocol to ethernet. */ | 2295 | /* Tunnel gso handlers can set protocol to ethernet. */ |
2296 | if (type == htons(ETH_P_TEB)) { | 2296 | if (type == htons(ETH_P_TEB)) { |
@@ -2303,15 +2303,30 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth) | |||
2303 | type = eth->h_proto; | 2303 | type = eth->h_proto; |
2304 | } | 2304 | } |
2305 | 2305 | ||
2306 | while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { | 2306 | /* if skb->protocol is 802.1Q/AD then the header should already be |
2307 | struct vlan_hdr *vh; | 2307 | * present at mac_len - VLAN_HLEN (if mac_len > 0), or at |
2308 | 2308 | * ETH_HLEN otherwise | |
2309 | if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) | 2309 | */ |
2310 | return 0; | 2310 | if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { |
2311 | 2311 | if (vlan_depth) { | |
2312 | vh = (struct vlan_hdr *)(skb->data + vlan_depth); | 2312 | if (unlikely(WARN_ON(vlan_depth < VLAN_HLEN))) |
2313 | type = vh->h_vlan_encapsulated_proto; | 2313 | return 0; |
2314 | vlan_depth += VLAN_HLEN; | 2314 | vlan_depth -= VLAN_HLEN; |
2315 | } else { | ||
2316 | vlan_depth = ETH_HLEN; | ||
2317 | } | ||
2318 | do { | ||
2319 | struct vlan_hdr *vh; | ||
2320 | |||
2321 | if (unlikely(!pskb_may_pull(skb, | ||
2322 | vlan_depth + VLAN_HLEN))) | ||
2323 | return 0; | ||
2324 | |||
2325 | vh = (struct vlan_hdr *)(skb->data + vlan_depth); | ||
2326 | type = vh->h_vlan_encapsulated_proto; | ||
2327 | vlan_depth += VLAN_HLEN; | ||
2328 | } while (type == htons(ETH_P_8021Q) || | ||
2329 | type == htons(ETH_P_8021AD)); | ||
2315 | } | 2330 | } |
2316 | 2331 | ||
2317 | *depth = vlan_depth; | 2332 | *depth = vlan_depth; |
diff --git a/net/core/filter.c b/net/core/filter.c index 842f8393121d..9de0c25323b4 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -1492,8 +1492,13 @@ static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp, | |||
1492 | fp->jited = 0; | 1492 | fp->jited = 0; |
1493 | 1493 | ||
1494 | err = sk_chk_filter(fp->insns, fp->len); | 1494 | err = sk_chk_filter(fp->insns, fp->len); |
1495 | if (err) | 1495 | if (err) { |
1496 | if (sk != NULL) | ||
1497 | sk_filter_uncharge(sk, fp); | ||
1498 | else | ||
1499 | kfree(fp); | ||
1496 | return ERR_PTR(err); | 1500 | return ERR_PTR(err); |
1501 | } | ||
1497 | 1502 | ||
1498 | /* Probe if we can JIT compile the filter and if so, do | 1503 | /* Probe if we can JIT compile the filter and if so, do |
1499 | * the compilation of the filter. | 1504 | * the compilation of the filter. |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index f31268dbc0d1..741b22c62acf 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -2045,11 +2045,15 @@ replay: | |||
2045 | if (ops->newlink) { | 2045 | if (ops->newlink) { |
2046 | err = ops->newlink(net, dev, tb, data); | 2046 | err = ops->newlink(net, dev, tb, data); |
2047 | /* Drivers should call free_netdev() in ->destructor | 2047 | /* Drivers should call free_netdev() in ->destructor |
2048 | * and unregister it on failure so that device could be | 2048 | * and unregister it on failure after registration |
2049 | * finally freed in rtnl_unlock. | 2049 | * so that device could be finally freed in rtnl_unlock. |
2050 | */ | 2050 | */ |
2051 | if (err < 0) | 2051 | if (err < 0) { |
2052 | /* If device is not registered at all, free it now */ | ||
2053 | if (dev->reg_state == NETREG_UNINITIALIZED) | ||
2054 | free_netdev(dev); | ||
2052 | goto out; | 2055 | goto out; |
2056 | } | ||
2053 | } else { | 2057 | } else { |
2054 | err = register_netdevice(dev); | 2058 | err = register_netdevice(dev); |
2055 | if (err < 0) { | 2059 | if (err < 0) { |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 350b2072f0ab..931529d5daa2 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2684,13 +2684,12 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack) | |||
2684 | bool recovered = !before(tp->snd_una, tp->high_seq); | 2684 | bool recovered = !before(tp->snd_una, tp->high_seq); |
2685 | 2685 | ||
2686 | if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */ | 2686 | if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */ |
2687 | if (flag & FLAG_ORIG_SACK_ACKED) { | 2687 | /* Step 3.b. A timeout is spurious if not all data are |
2688 | /* Step 3.b. A timeout is spurious if not all data are | 2688 | * lost, i.e., never-retransmitted data are (s)acked. |
2689 | * lost, i.e., never-retransmitted data are (s)acked. | 2689 | */ |
2690 | */ | 2690 | if (tcp_try_undo_loss(sk, flag & FLAG_ORIG_SACK_ACKED)) |
2691 | tcp_try_undo_loss(sk, true); | ||
2692 | return; | 2691 | return; |
2693 | } | 2692 | |
2694 | if (after(tp->snd_nxt, tp->high_seq) && | 2693 | if (after(tp->snd_nxt, tp->high_seq) && |
2695 | (flag & FLAG_DATA_SACKED || is_dupack)) { | 2694 | (flag & FLAG_DATA_SACKED || is_dupack)) { |
2696 | tp->frto = 0; /* Loss was real: 2nd part of step 3.a */ | 2695 | tp->frto = 0; /* Loss was real: 2nd part of step 3.a */ |
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 6179ac186ab9..ffa029305a09 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <net/addrconf.h> | 8 | #include <net/addrconf.h> |
9 | #include <net/secure_seq.h> | 9 | #include <net/secure_seq.h> |
10 | 10 | ||
11 | |||
12 | int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | 11 | int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) |
13 | { | 12 | { |
14 | u16 offset = sizeof(struct ipv6hdr); | 13 | u16 offset = sizeof(struct ipv6hdr); |
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index d9da8c448c76..e6836755c45d 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -1392,15 +1392,19 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1392 | 1392 | ||
1393 | if (ipip) { | 1393 | if (ipip) { |
1394 | __be32 info = ic->un.gateway; | 1394 | __be32 info = ic->un.gateway; |
1395 | __u8 type = ic->type; | ||
1396 | __u8 code = ic->code; | ||
1395 | 1397 | ||
1396 | /* Update the MTU */ | 1398 | /* Update the MTU */ |
1397 | if (ic->type == ICMP_DEST_UNREACH && | 1399 | if (ic->type == ICMP_DEST_UNREACH && |
1398 | ic->code == ICMP_FRAG_NEEDED) { | 1400 | ic->code == ICMP_FRAG_NEEDED) { |
1399 | struct ip_vs_dest *dest = cp->dest; | 1401 | struct ip_vs_dest *dest = cp->dest; |
1400 | u32 mtu = ntohs(ic->un.frag.mtu); | 1402 | u32 mtu = ntohs(ic->un.frag.mtu); |
1403 | __be16 frag_off = cih->frag_off; | ||
1401 | 1404 | ||
1402 | /* Strip outer IP and ICMP, go to IPIP header */ | 1405 | /* Strip outer IP and ICMP, go to IPIP header */ |
1403 | __skb_pull(skb, ihl + sizeof(_icmph)); | 1406 | if (pskb_pull(skb, ihl + sizeof(_icmph)) == NULL) |
1407 | goto ignore_ipip; | ||
1404 | offset2 -= ihl + sizeof(_icmph); | 1408 | offset2 -= ihl + sizeof(_icmph); |
1405 | skb_reset_network_header(skb); | 1409 | skb_reset_network_header(skb); |
1406 | IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n", | 1410 | IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n", |
@@ -1408,7 +1412,7 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1408 | ipv4_update_pmtu(skb, dev_net(skb->dev), | 1412 | ipv4_update_pmtu(skb, dev_net(skb->dev), |
1409 | mtu, 0, 0, 0, 0); | 1413 | mtu, 0, 0, 0, 0); |
1410 | /* Client uses PMTUD? */ | 1414 | /* Client uses PMTUD? */ |
1411 | if (!(cih->frag_off & htons(IP_DF))) | 1415 | if (!(frag_off & htons(IP_DF))) |
1412 | goto ignore_ipip; | 1416 | goto ignore_ipip; |
1413 | /* Prefer the resulting PMTU */ | 1417 | /* Prefer the resulting PMTU */ |
1414 | if (dest) { | 1418 | if (dest) { |
@@ -1427,12 +1431,13 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) | |||
1427 | /* Strip outer IP, ICMP and IPIP, go to IP header of | 1431 | /* Strip outer IP, ICMP and IPIP, go to IP header of |
1428 | * original request. | 1432 | * original request. |
1429 | */ | 1433 | */ |
1430 | __skb_pull(skb, offset2); | 1434 | if (pskb_pull(skb, offset2) == NULL) |
1435 | goto ignore_ipip; | ||
1431 | skb_reset_network_header(skb); | 1436 | skb_reset_network_header(skb); |
1432 | IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n", | 1437 | IP_VS_DBG(12, "Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n", |
1433 | &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, | 1438 | &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, |
1434 | ic->type, ic->code, ntohl(info)); | 1439 | type, code, ntohl(info)); |
1435 | icmp_send(skb, ic->type, ic->code, info); | 1440 | icmp_send(skb, type, code, info); |
1436 | /* ICMP can be shorter but anyways, account it */ | 1441 | /* ICMP can be shorter but anyways, account it */ |
1437 | ip_vs_out_stats(cp, skb); | 1442 | ip_vs_out_stats(cp, skb); |
1438 | 1443 | ||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index e0ccd84d4d67..15c731f03fa6 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1377,7 +1377,9 @@ retry: | |||
1377 | bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, | 1377 | bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, |
1378 | struct user_namespace *user_ns, int cap) | 1378 | struct user_namespace *user_ns, int cap) |
1379 | { | 1379 | { |
1380 | return sk_ns_capable(nsp->sk, user_ns, cap); | 1380 | return ((nsp->flags & NETLINK_SKB_DST) || |
1381 | file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) && | ||
1382 | ns_capable(user_ns, cap); | ||
1381 | } | 1383 | } |
1382 | EXPORT_SYMBOL(__netlink_ns_capable); | 1384 | EXPORT_SYMBOL(__netlink_ns_capable); |
1383 | 1385 | ||
@@ -2323,6 +2325,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
2323 | struct sk_buff *skb; | 2325 | struct sk_buff *skb; |
2324 | int err; | 2326 | int err; |
2325 | struct scm_cookie scm; | 2327 | struct scm_cookie scm; |
2328 | u32 netlink_skb_flags = 0; | ||
2326 | 2329 | ||
2327 | if (msg->msg_flags&MSG_OOB) | 2330 | if (msg->msg_flags&MSG_OOB) |
2328 | return -EOPNOTSUPP; | 2331 | return -EOPNOTSUPP; |
@@ -2344,6 +2347,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
2344 | if ((dst_group || dst_portid) && | 2347 | if ((dst_group || dst_portid) && |
2345 | !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) | 2348 | !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) |
2346 | goto out; | 2349 | goto out; |
2350 | netlink_skb_flags |= NETLINK_SKB_DST; | ||
2347 | } else { | 2351 | } else { |
2348 | dst_portid = nlk->dst_portid; | 2352 | dst_portid = nlk->dst_portid; |
2349 | dst_group = nlk->dst_group; | 2353 | dst_group = nlk->dst_group; |
@@ -2373,6 +2377,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
2373 | NETLINK_CB(skb).portid = nlk->portid; | 2377 | NETLINK_CB(skb).portid = nlk->portid; |
2374 | NETLINK_CB(skb).dst_group = dst_group; | 2378 | NETLINK_CB(skb).dst_group = dst_group; |
2375 | NETLINK_CB(skb).creds = siocb->scm->creds; | 2379 | NETLINK_CB(skb).creds = siocb->scm->creds; |
2380 | NETLINK_CB(skb).flags = netlink_skb_flags; | ||
2376 | 2381 | ||
2377 | err = -EFAULT; | 2382 | err = -EFAULT; |
2378 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | 2383 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index fd9a16a6d1de..412d9dc3a873 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -947,6 +947,20 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, | |||
947 | return skb; | 947 | return skb; |
948 | } | 948 | } |
949 | 949 | ||
950 | /* A wrapper for nlmsg_multicast() checking that nlsk is still available. | ||
951 | * Must be called with RCU read lock. | ||
952 | */ | ||
953 | static inline int xfrm_nlmsg_multicast(struct net *net, struct sk_buff *skb, | ||
954 | u32 pid, unsigned int group) | ||
955 | { | ||
956 | struct sock *nlsk = rcu_dereference(net->xfrm.nlsk); | ||
957 | |||
958 | if (nlsk) | ||
959 | return nlmsg_multicast(nlsk, skb, pid, group, GFP_ATOMIC); | ||
960 | else | ||
961 | return -1; | ||
962 | } | ||
963 | |||
950 | static inline size_t xfrm_spdinfo_msgsize(void) | 964 | static inline size_t xfrm_spdinfo_msgsize(void) |
951 | { | 965 | { |
952 | return NLMSG_ALIGN(4) | 966 | return NLMSG_ALIGN(4) |
@@ -2228,7 +2242,7 @@ static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, | |||
2228 | if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0) | 2242 | if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0) |
2229 | BUG(); | 2243 | BUG(); |
2230 | 2244 | ||
2231 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC); | 2245 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MIGRATE); |
2232 | } | 2246 | } |
2233 | #else | 2247 | #else |
2234 | static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, | 2248 | static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, |
@@ -2419,7 +2433,7 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, const struct km_event *c) | |||
2419 | return -EMSGSIZE; | 2433 | return -EMSGSIZE; |
2420 | } | 2434 | } |
2421 | 2435 | ||
2422 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 2436 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE); |
2423 | } | 2437 | } |
2424 | 2438 | ||
2425 | static int xfrm_aevent_state_notify(struct xfrm_state *x, const struct km_event *c) | 2439 | static int xfrm_aevent_state_notify(struct xfrm_state *x, const struct km_event *c) |
@@ -2434,7 +2448,7 @@ static int xfrm_aevent_state_notify(struct xfrm_state *x, const struct km_event | |||
2434 | if (build_aevent(skb, x, c) < 0) | 2448 | if (build_aevent(skb, x, c) < 0) |
2435 | BUG(); | 2449 | BUG(); |
2436 | 2450 | ||
2437 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); | 2451 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_AEVENTS); |
2438 | } | 2452 | } |
2439 | 2453 | ||
2440 | static int xfrm_notify_sa_flush(const struct km_event *c) | 2454 | static int xfrm_notify_sa_flush(const struct km_event *c) |
@@ -2460,7 +2474,7 @@ static int xfrm_notify_sa_flush(const struct km_event *c) | |||
2460 | 2474 | ||
2461 | nlmsg_end(skb, nlh); | 2475 | nlmsg_end(skb, nlh); |
2462 | 2476 | ||
2463 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); | 2477 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA); |
2464 | } | 2478 | } |
2465 | 2479 | ||
2466 | static inline size_t xfrm_sa_len(struct xfrm_state *x) | 2480 | static inline size_t xfrm_sa_len(struct xfrm_state *x) |
@@ -2547,7 +2561,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, const struct km_event *c) | |||
2547 | 2561 | ||
2548 | nlmsg_end(skb, nlh); | 2562 | nlmsg_end(skb, nlh); |
2549 | 2563 | ||
2550 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); | 2564 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA); |
2551 | 2565 | ||
2552 | out_free_skb: | 2566 | out_free_skb: |
2553 | kfree_skb(skb); | 2567 | kfree_skb(skb); |
@@ -2638,7 +2652,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | |||
2638 | if (build_acquire(skb, x, xt, xp) < 0) | 2652 | if (build_acquire(skb, x, xt, xp) < 0) |
2639 | BUG(); | 2653 | BUG(); |
2640 | 2654 | ||
2641 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); | 2655 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_ACQUIRE); |
2642 | } | 2656 | } |
2643 | 2657 | ||
2644 | /* User gives us xfrm_user_policy_info followed by an array of 0 | 2658 | /* User gives us xfrm_user_policy_info followed by an array of 0 |
@@ -2752,7 +2766,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, const struct | |||
2752 | if (build_polexpire(skb, xp, dir, c) < 0) | 2766 | if (build_polexpire(skb, xp, dir, c) < 0) |
2753 | BUG(); | 2767 | BUG(); |
2754 | 2768 | ||
2755 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 2769 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE); |
2756 | } | 2770 | } |
2757 | 2771 | ||
2758 | static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_event *c) | 2772 | static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_event *c) |
@@ -2814,7 +2828,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_e | |||
2814 | 2828 | ||
2815 | nlmsg_end(skb, nlh); | 2829 | nlmsg_end(skb, nlh); |
2816 | 2830 | ||
2817 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2831 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY); |
2818 | 2832 | ||
2819 | out_free_skb: | 2833 | out_free_skb: |
2820 | kfree_skb(skb); | 2834 | kfree_skb(skb); |
@@ -2842,7 +2856,7 @@ static int xfrm_notify_policy_flush(const struct km_event *c) | |||
2842 | 2856 | ||
2843 | nlmsg_end(skb, nlh); | 2857 | nlmsg_end(skb, nlh); |
2844 | 2858 | ||
2845 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2859 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY); |
2846 | 2860 | ||
2847 | out_free_skb: | 2861 | out_free_skb: |
2848 | kfree_skb(skb); | 2862 | kfree_skb(skb); |
@@ -2911,7 +2925,7 @@ static int xfrm_send_report(struct net *net, u8 proto, | |||
2911 | if (build_report(skb, proto, sel, addr) < 0) | 2925 | if (build_report(skb, proto, sel, addr) < 0) |
2912 | BUG(); | 2926 | BUG(); |
2913 | 2927 | ||
2914 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); | 2928 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_REPORT); |
2915 | } | 2929 | } |
2916 | 2930 | ||
2917 | static inline size_t xfrm_mapping_msgsize(void) | 2931 | static inline size_t xfrm_mapping_msgsize(void) |
@@ -2963,7 +2977,7 @@ static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, | |||
2963 | if (build_mapping(skb, x, ipaddr, sport) < 0) | 2977 | if (build_mapping(skb, x, ipaddr, sport) < 0) |
2964 | BUG(); | 2978 | BUG(); |
2965 | 2979 | ||
2966 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MAPPING, GFP_ATOMIC); | 2980 | return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MAPPING); |
2967 | } | 2981 | } |
2968 | 2982 | ||
2969 | static bool xfrm_is_alive(const struct km_event *c) | 2983 | static bool xfrm_is_alive(const struct km_event *c) |