aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-09-26 19:08:27 -0400
committerDavid S. Miller <davem@davemloft.net>2015-09-26 19:08:27 -0400
commit4963ed48f2c20196d51a447ee87dc2815584fee4 (patch)
treea1902f466dafa00453889a4f1e66b00249ce0529 /net/netlink
parent4d54d86546f62c7c4a0fe3b36a64c5e3b98ce1a9 (diff)
parent518a7cb6980cd640c7f979d29021ad870f60d7d7 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts: net/ipv4/arp.c The net/ipv4/arp.c conflict was one commit adding a new local variable while another commit was deleting one. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r--net/netlink/af_netlink.c63
-rw-r--r--net/netlink/af_netlink.h10
2 files changed, 59 insertions, 14 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 7f86d3b55060..8f060d7f9a0e 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -125,6 +125,24 @@ static inline u32 netlink_group_mask(u32 group)
125 return group ? 1 << (group - 1) : 0; 125 return group ? 1 << (group - 1) : 0;
126} 126}
127 127
128static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb,
129 gfp_t gfp_mask)
130{
131 unsigned int len = skb_end_offset(skb);
132 struct sk_buff *new;
133
134 new = alloc_skb(len, gfp_mask);
135 if (new == NULL)
136 return NULL;
137
138 NETLINK_CB(new).portid = NETLINK_CB(skb).portid;
139 NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group;
140 NETLINK_CB(new).creds = NETLINK_CB(skb).creds;
141
142 memcpy(skb_put(new, len), skb->data, len);
143 return new;
144}
145
128int netlink_add_tap(struct netlink_tap *nt) 146int netlink_add_tap(struct netlink_tap *nt)
129{ 147{
130 if (unlikely(nt->dev->type != ARPHRD_NETLINK)) 148 if (unlikely(nt->dev->type != ARPHRD_NETLINK))
@@ -206,7 +224,11 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb,
206 int ret = -ENOMEM; 224 int ret = -ENOMEM;
207 225
208 dev_hold(dev); 226 dev_hold(dev);
209 nskb = skb_clone(skb, GFP_ATOMIC); 227
228 if (netlink_skb_is_mmaped(skb) || is_vmalloc_addr(skb->head))
229 nskb = netlink_to_full_skb(skb, GFP_ATOMIC);
230 else
231 nskb = skb_clone(skb, GFP_ATOMIC);
210 if (nskb) { 232 if (nskb) {
211 nskb->dev = dev; 233 nskb->dev = dev;
212 nskb->protocol = htons((u16) sk->sk_protocol); 234 nskb->protocol = htons((u16) sk->sk_protocol);
@@ -279,11 +301,6 @@ static void netlink_rcv_wake(struct sock *sk)
279} 301}
280 302
281#ifdef CONFIG_NETLINK_MMAP 303#ifdef CONFIG_NETLINK_MMAP
282static bool netlink_skb_is_mmaped(const struct sk_buff *skb)
283{
284 return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED;
285}
286
287static bool netlink_rx_is_mmaped(struct sock *sk) 304static bool netlink_rx_is_mmaped(struct sock *sk)
288{ 305{
289 return nlk_sk(sk)->rx_ring.pg_vec != NULL; 306 return nlk_sk(sk)->rx_ring.pg_vec != NULL;
@@ -846,7 +863,6 @@ static void netlink_ring_set_copied(struct sock *sk, struct sk_buff *skb)
846} 863}
847 864
848#else /* CONFIG_NETLINK_MMAP */ 865#else /* CONFIG_NETLINK_MMAP */
849#define netlink_skb_is_mmaped(skb) false
850#define netlink_rx_is_mmaped(sk) false 866#define netlink_rx_is_mmaped(sk) false
851#define netlink_tx_is_mmaped(sk) false 867#define netlink_tx_is_mmaped(sk) false
852#define netlink_mmap sock_no_mmap 868#define netlink_mmap sock_no_mmap
@@ -1094,8 +1110,8 @@ static int netlink_insert(struct sock *sk, u32 portid)
1094 1110
1095 lock_sock(sk); 1111 lock_sock(sk);
1096 1112
1097 err = -EBUSY; 1113 err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY;
1098 if (nlk_sk(sk)->portid) 1114 if (nlk_sk(sk)->bound)
1099 goto err; 1115 goto err;
1100 1116
1101 err = -ENOMEM; 1117 err = -ENOMEM;
@@ -1115,10 +1131,14 @@ static int netlink_insert(struct sock *sk, u32 portid)
1115 err = -EOVERFLOW; 1131 err = -EOVERFLOW;
1116 if (err == -EEXIST) 1132 if (err == -EEXIST)
1117 err = -EADDRINUSE; 1133 err = -EADDRINUSE;
1118 nlk_sk(sk)->portid = 0;
1119 sock_put(sk); 1134 sock_put(sk);
1135 goto err;
1120 } 1136 }
1121 1137
1138 /* We need to ensure that the socket is hashed and visible. */
1139 smp_wmb();
1140 nlk_sk(sk)->bound = portid;
1141
1122err: 1142err:
1123 release_sock(sk); 1143 release_sock(sk);
1124 return err; 1144 return err;
@@ -1503,6 +1523,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
1503 struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; 1523 struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
1504 int err; 1524 int err;
1505 long unsigned int groups = nladdr->nl_groups; 1525 long unsigned int groups = nladdr->nl_groups;
1526 bool bound;
1506 1527
1507 if (addr_len < sizeof(struct sockaddr_nl)) 1528 if (addr_len < sizeof(struct sockaddr_nl))
1508 return -EINVAL; 1529 return -EINVAL;
@@ -1519,9 +1540,14 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
1519 return err; 1540 return err;
1520 } 1541 }
1521 1542
1522 if (nlk->portid) 1543 bound = nlk->bound;
1544 if (bound) {
1545 /* Ensure nlk->portid is up-to-date. */
1546 smp_rmb();
1547
1523 if (nladdr->nl_pid != nlk->portid) 1548 if (nladdr->nl_pid != nlk->portid)
1524 return -EINVAL; 1549 return -EINVAL;
1550 }
1525 1551
1526 if (nlk->netlink_bind && groups) { 1552 if (nlk->netlink_bind && groups) {
1527 int group; 1553 int group;
@@ -1537,7 +1563,10 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
1537 } 1563 }
1538 } 1564 }
1539 1565
1540 if (!nlk->portid) { 1566 /* No need for barriers here as we return to user-space without
1567 * using any of the bound attributes.
1568 */
1569 if (!bound) {
1541 err = nladdr->nl_pid ? 1570 err = nladdr->nl_pid ?
1542 netlink_insert(sk, nladdr->nl_pid) : 1571 netlink_insert(sk, nladdr->nl_pid) :
1543 netlink_autobind(sock); 1572 netlink_autobind(sock);
@@ -1585,7 +1614,10 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
1585 !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) 1614 !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
1586 return -EPERM; 1615 return -EPERM;
1587 1616
1588 if (!nlk->portid) 1617 /* No need for barriers here as we return to user-space without
1618 * using any of the bound attributes.
1619 */
1620 if (!nlk->bound)
1589 err = netlink_autobind(sock); 1621 err = netlink_autobind(sock);
1590 1622
1591 if (err == 0) { 1623 if (err == 0) {
@@ -2426,10 +2458,13 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
2426 dst_group = nlk->dst_group; 2458 dst_group = nlk->dst_group;
2427 } 2459 }
2428 2460
2429 if (!nlk->portid) { 2461 if (!nlk->bound) {
2430 err = netlink_autobind(sock); 2462 err = netlink_autobind(sock);
2431 if (err) 2463 if (err)
2432 goto out; 2464 goto out;
2465 } else {
2466 /* Ensure nlk is hashed and visible. */
2467 smp_rmb();
2433 } 2468 }
2434 2469
2435 /* It's a really convoluted way for userland to ask for mmaped 2470 /* It's a really convoluted way for userland to ask for mmaped
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
index 89008405d6b4..14437d9b1965 100644
--- a/net/netlink/af_netlink.h
+++ b/net/netlink/af_netlink.h
@@ -35,6 +35,7 @@ struct netlink_sock {
35 unsigned long state; 35 unsigned long state;
36 size_t max_recvmsg_len; 36 size_t max_recvmsg_len;
37 wait_queue_head_t wait; 37 wait_queue_head_t wait;
38 bool bound;
38 bool cb_running; 39 bool cb_running;
39 struct netlink_callback cb; 40 struct netlink_callback cb;
40 struct mutex *cb_mutex; 41 struct mutex *cb_mutex;
@@ -59,6 +60,15 @@ static inline struct netlink_sock *nlk_sk(struct sock *sk)
59 return container_of(sk, struct netlink_sock, sk); 60 return container_of(sk, struct netlink_sock, sk);
60} 61}
61 62
63static inline bool netlink_skb_is_mmaped(const struct sk_buff *skb)
64{
65#ifdef CONFIG_NETLINK_MMAP
66 return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED;
67#else
68 return false;
69#endif /* CONFIG_NETLINK_MMAP */
70}
71
62struct netlink_table { 72struct netlink_table {
63 struct rhashtable hash; 73 struct rhashtable hash;
64 struct hlist_head mc_list; 74 struct hlist_head mc_list;