|
Lines 123-146
Link Here
|
| 123 |
return group ? 1 << (group - 1) : 0; |
123 |
return group ? 1 << (group - 1) : 0; |
| 124 |
} |
124 |
} |
| 125 |
|
125 |
|
| 126 |
static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb, |
|
|
| 127 |
gfp_t gfp_mask) |
| 128 |
{ |
| 129 |
unsigned int len = skb_end_offset(skb); |
| 130 |
struct sk_buff *new; |
| 131 |
|
| 132 |
new = alloc_skb(len, gfp_mask); |
| 133 |
if (new == NULL) |
| 134 |
return NULL; |
| 135 |
|
| 136 |
NETLINK_CB(new).portid = NETLINK_CB(skb).portid; |
| 137 |
NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group; |
| 138 |
NETLINK_CB(new).creds = NETLINK_CB(skb).creds; |
| 139 |
|
| 140 |
memcpy(skb_put(new, len), skb->data, len); |
| 141 |
return new; |
| 142 |
} |
| 143 |
|
| 144 |
int netlink_add_tap(struct netlink_tap *nt) |
126 |
int netlink_add_tap(struct netlink_tap *nt) |
| 145 |
{ |
127 |
{ |
| 146 |
if (unlikely(nt->dev->type != ARPHRD_NETLINK)) |
128 |
if (unlikely(nt->dev->type != ARPHRD_NETLINK)) |
|
Lines 222-232
Link Here
|
| 222 |
int ret = -ENOMEM; |
204 |
int ret = -ENOMEM; |
| 223 |
|
205 |
|
| 224 |
dev_hold(dev); |
206 |
dev_hold(dev); |
| 225 |
|
207 |
nskb = skb_clone(skb, GFP_ATOMIC); |
| 226 |
if (netlink_skb_is_mmaped(skb) || is_vmalloc_addr(skb->head)) |
|
|
| 227 |
nskb = netlink_to_full_skb(skb, GFP_ATOMIC); |
| 228 |
else |
| 229 |
nskb = skb_clone(skb, GFP_ATOMIC); |
| 230 |
if (nskb) { |
208 |
if (nskb) { |
| 231 |
nskb->dev = dev; |
209 |
nskb->dev = dev; |
| 232 |
nskb->protocol = htons((u16) sk->sk_protocol); |
210 |
nskb->protocol = htons((u16) sk->sk_protocol); |
|
Lines 298-303
Link Here
|
| 298 |
} |
276 |
} |
| 299 |
|
277 |
|
| 300 |
#ifdef CONFIG_NETLINK_MMAP |
278 |
#ifdef CONFIG_NETLINK_MMAP |
|
|
279 |
static bool netlink_skb_is_mmaped(const struct sk_buff *skb) |
| 280 |
{ |
| 281 |
return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED; |
| 282 |
} |
| 283 |
|
| 301 |
static bool netlink_rx_is_mmaped(struct sock *sk) |
284 |
static bool netlink_rx_is_mmaped(struct sock *sk) |
| 302 |
{ |
285 |
{ |
| 303 |
return nlk_sk(sk)->rx_ring.pg_vec != NULL; |
286 |
return nlk_sk(sk)->rx_ring.pg_vec != NULL; |
|
Lines 372-423
Link Here
|
| 372 |
return NULL; |
355 |
return NULL; |
| 373 |
} |
356 |
} |
| 374 |
|
357 |
|
| 375 |
|
|
|
| 376 |
static void |
| 377 |
__netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, bool tx_ring, void **pg_vec, |
| 378 |
unsigned int order) |
| 379 |
{ |
| 380 |
struct netlink_sock *nlk = nlk_sk(sk); |
| 381 |
struct sk_buff_head *queue; |
| 382 |
struct netlink_ring *ring; |
| 383 |
|
| 384 |
queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue; |
| 385 |
ring = tx_ring ? &nlk->tx_ring : &nlk->rx_ring; |
| 386 |
|
| 387 |
spin_lock_bh(&queue->lock); |
| 388 |
|
| 389 |
ring->frame_max = req->nm_frame_nr - 1; |
| 390 |
ring->head = 0; |
| 391 |
ring->frame_size = req->nm_frame_size; |
| 392 |
ring->pg_vec_pages = req->nm_block_size / PAGE_SIZE; |
| 393 |
|
| 394 |
swap(ring->pg_vec_len, req->nm_block_nr); |
| 395 |
swap(ring->pg_vec_order, order); |
| 396 |
swap(ring->pg_vec, pg_vec); |
| 397 |
|
| 398 |
__skb_queue_purge(queue); |
| 399 |
spin_unlock_bh(&queue->lock); |
| 400 |
|
| 401 |
WARN_ON(atomic_read(&nlk->mapped)); |
| 402 |
|
| 403 |
if (pg_vec) |
| 404 |
free_pg_vec(pg_vec, order, req->nm_block_nr); |
| 405 |
} |
| 406 |
|
| 407 |
static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, |
358 |
static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, |
| 408 |
bool tx_ring) |
359 |
bool closing, bool tx_ring) |
| 409 |
{ |
360 |
{ |
| 410 |
struct netlink_sock *nlk = nlk_sk(sk); |
361 |
struct netlink_sock *nlk = nlk_sk(sk); |
| 411 |
struct netlink_ring *ring; |
362 |
struct netlink_ring *ring; |
|
|
363 |
struct sk_buff_head *queue; |
| 412 |
void **pg_vec = NULL; |
364 |
void **pg_vec = NULL; |
| 413 |
unsigned int order = 0; |
365 |
unsigned int order = 0; |
|
|
366 |
int err; |
| 414 |
|
367 |
|
| 415 |
ring = tx_ring ? &nlk->tx_ring : &nlk->rx_ring; |
368 |
ring = tx_ring ? &nlk->tx_ring : &nlk->rx_ring; |
|
|
369 |
queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue; |
| 416 |
|
370 |
|
| 417 |
if (atomic_read(&nlk->mapped)) |
371 |
if (!closing) { |
| 418 |
return -EBUSY; |
372 |
if (atomic_read(&nlk->mapped)) |
| 419 |
if (atomic_read(&ring->pending)) |
373 |
return -EBUSY; |
| 420 |
return -EBUSY; |
374 |
if (atomic_read(&ring->pending)) |
|
|
375 |
return -EBUSY; |
| 376 |
} |
| 421 |
|
377 |
|
| 422 |
if (req->nm_block_nr) { |
378 |
if (req->nm_block_nr) { |
| 423 |
if (ring->pg_vec != NULL) |
379 |
if (ring->pg_vec != NULL) |
|
Lines 449-467
Link Here
|
| 449 |
return -EINVAL; |
405 |
return -EINVAL; |
| 450 |
} |
406 |
} |
| 451 |
|
407 |
|
|
|
408 |
err = -EBUSY; |
| 452 |
mutex_lock(&nlk->pg_vec_lock); |
409 |
mutex_lock(&nlk->pg_vec_lock); |
| 453 |
if (atomic_read(&nlk->mapped) == 0) { |
410 |
if (closing || atomic_read(&nlk->mapped) == 0) { |
| 454 |
__netlink_set_ring(sk, req, tx_ring, pg_vec, order); |
411 |
err = 0; |
| 455 |
mutex_unlock(&nlk->pg_vec_lock); |
412 |
spin_lock_bh(&queue->lock); |
| 456 |
return 0; |
413 |
|
| 457 |
} |
414 |
ring->frame_max = req->nm_frame_nr - 1; |
|
|
415 |
ring->head = 0; |
| 416 |
ring->frame_size = req->nm_frame_size; |
| 417 |
ring->pg_vec_pages = req->nm_block_size / PAGE_SIZE; |
| 418 |
|
| 419 |
swap(ring->pg_vec_len, req->nm_block_nr); |
| 420 |
swap(ring->pg_vec_order, order); |
| 421 |
swap(ring->pg_vec, pg_vec); |
| 422 |
|
| 423 |
__skb_queue_purge(queue); |
| 424 |
spin_unlock_bh(&queue->lock); |
| 458 |
|
425 |
|
|
|
426 |
WARN_ON(atomic_read(&nlk->mapped)); |
| 427 |
} |
| 459 |
mutex_unlock(&nlk->pg_vec_lock); |
428 |
mutex_unlock(&nlk->pg_vec_lock); |
| 460 |
|
429 |
|
| 461 |
if (pg_vec) |
430 |
if (pg_vec) |
| 462 |
free_pg_vec(pg_vec, order, req->nm_block_nr); |
431 |
free_pg_vec(pg_vec, order, req->nm_block_nr); |
| 463 |
|
432 |
return err; |
| 464 |
return -EBUSY; |
|
|
| 465 |
} |
433 |
} |
| 466 |
|
434 |
|
| 467 |
static void netlink_mm_open(struct vm_area_struct *vma) |
435 |
static void netlink_mm_open(struct vm_area_struct *vma) |
|
Lines 849-854
Link Here
|
| 849 |
} |
817 |
} |
| 850 |
|
818 |
|
| 851 |
#else /* CONFIG_NETLINK_MMAP */ |
819 |
#else /* CONFIG_NETLINK_MMAP */ |
|
|
820 |
#define netlink_skb_is_mmaped(skb) false |
| 852 |
#define netlink_rx_is_mmaped(sk) false |
821 |
#define netlink_rx_is_mmaped(sk) false |
| 853 |
#define netlink_tx_is_mmaped(sk) false |
822 |
#define netlink_tx_is_mmaped(sk) false |
| 854 |
#define netlink_mmap sock_no_mmap |
823 |
#define netlink_mmap sock_no_mmap |
|
Lines 929-938
Link Here
|
| 929 |
|
898 |
|
| 930 |
memset(&req, 0, sizeof(req)); |
899 |
memset(&req, 0, sizeof(req)); |
| 931 |
if (nlk->rx_ring.pg_vec) |
900 |
if (nlk->rx_ring.pg_vec) |
| 932 |
__netlink_set_ring(sk, &req, false, NULL, 0); |
901 |
netlink_set_ring(sk, &req, true, false); |
| 933 |
memset(&req, 0, sizeof(req)); |
902 |
memset(&req, 0, sizeof(req)); |
| 934 |
if (nlk->tx_ring.pg_vec) |
903 |
if (nlk->tx_ring.pg_vec) |
| 935 |
__netlink_set_ring(sk, &req, true, NULL, 0); |
904 |
netlink_set_ring(sk, &req, true, true); |
| 936 |
} |
905 |
} |
| 937 |
#endif /* CONFIG_NETLINK_MMAP */ |
906 |
#endif /* CONFIG_NETLINK_MMAP */ |
| 938 |
|
907 |
|
|
Lines 1096-1103
Link Here
|
| 1096 |
|
1065 |
|
| 1097 |
lock_sock(sk); |
1066 |
lock_sock(sk); |
| 1098 |
|
1067 |
|
| 1099 |
err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY; |
1068 |
err = -EBUSY; |
| 1100 |
if (nlk_sk(sk)->bound) |
1069 |
if (nlk_sk(sk)->portid) |
| 1101 |
goto err; |
1070 |
goto err; |
| 1102 |
|
1071 |
|
| 1103 |
err = -ENOMEM; |
1072 |
err = -ENOMEM; |
|
Lines 1110-1129
Link Here
|
| 1110 |
|
1079 |
|
| 1111 |
err = __netlink_insert(table, sk); |
1080 |
err = __netlink_insert(table, sk); |
| 1112 |
if (err) { |
1081 |
if (err) { |
| 1113 |
/* In case the hashtable backend returns with -EBUSY |
|
|
| 1114 |
* from here, it must not escape to the caller. |
| 1115 |
*/ |
| 1116 |
if (unlikely(err == -EBUSY)) |
| 1117 |
err = -EOVERFLOW; |
| 1118 |
if (err == -EEXIST) |
1082 |
if (err == -EEXIST) |
| 1119 |
err = -EADDRINUSE; |
1083 |
err = -EADDRINUSE; |
|
|
1084 |
nlk_sk(sk)->portid = 0; |
| 1120 |
sock_put(sk); |
1085 |
sock_put(sk); |
| 1121 |
} |
1086 |
} |
| 1122 |
|
1087 |
|
| 1123 |
/* We need to ensure that the socket is hashed and visible. */ |
|
|
| 1124 |
smp_wmb(); |
| 1125 |
nlk_sk(sk)->bound = portid; |
| 1126 |
|
| 1127 |
err: |
1088 |
err: |
| 1128 |
release_sock(sk); |
1089 |
release_sock(sk); |
| 1129 |
return err; |
1090 |
return err; |
|
Lines 1503-1509
Link Here
|
| 1503 |
struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
1464 |
struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
| 1504 |
int err; |
1465 |
int err; |
| 1505 |
long unsigned int groups = nladdr->nl_groups; |
1466 |
long unsigned int groups = nladdr->nl_groups; |
| 1506 |
bool bound; |
|
|
| 1507 |
|
1467 |
|
| 1508 |
if (addr_len < sizeof(struct sockaddr_nl)) |
1468 |
if (addr_len < sizeof(struct sockaddr_nl)) |
| 1509 |
return -EINVAL; |
1469 |
return -EINVAL; |
|
Lines 1520-1533
Link Here
|
| 1520 |
return err; |
1480 |
return err; |
| 1521 |
} |
1481 |
} |
| 1522 |
|
1482 |
|
| 1523 |
bound = nlk->bound; |
1483 |
if (nlk->portid) |
| 1524 |
if (bound) { |
|
|
| 1525 |
/* Ensure nlk->portid is up-to-date. */ |
| 1526 |
smp_rmb(); |
| 1527 |
|
| 1528 |
if (nladdr->nl_pid != nlk->portid) |
1484 |
if (nladdr->nl_pid != nlk->portid) |
| 1529 |
return -EINVAL; |
1485 |
return -EINVAL; |
| 1530 |
} |
|
|
| 1531 |
|
1486 |
|
| 1532 |
if (nlk->netlink_bind && groups) { |
1487 |
if (nlk->netlink_bind && groups) { |
| 1533 |
int group; |
1488 |
int group; |
|
Lines 1543-1552
Link Here
|
| 1543 |
} |
1498 |
} |
| 1544 |
} |
1499 |
} |
| 1545 |
|
1500 |
|
| 1546 |
/* No need for barriers here as we return to user-space without |
1501 |
if (!nlk->portid) { |
| 1547 |
* using any of the bound attributes. |
|
|
| 1548 |
*/ |
| 1549 |
if (!bound) { |
| 1550 |
err = nladdr->nl_pid ? |
1502 |
err = nladdr->nl_pid ? |
| 1551 |
netlink_insert(sk, nladdr->nl_pid) : |
1503 |
netlink_insert(sk, nladdr->nl_pid) : |
| 1552 |
netlink_autobind(sock); |
1504 |
netlink_autobind(sock); |
|
Lines 1594-1603
Link Here
|
| 1594 |
!netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) |
1546 |
!netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) |
| 1595 |
return -EPERM; |
1547 |
return -EPERM; |
| 1596 |
|
1548 |
|
| 1597 |
/* No need for barriers here as we return to user-space without |
1549 |
if (!nlk->portid) |
| 1598 |
* using any of the bound attributes. |
|
|
| 1599 |
*/ |
| 1600 |
if (!nlk->bound) |
| 1601 |
err = netlink_autobind(sock); |
1550 |
err = netlink_autobind(sock); |
| 1602 |
|
1551 |
|
| 1603 |
if (err == 0) { |
1552 |
if (err == 0) { |
|
Lines 2248-2254
Link Here
|
| 2248 |
return -EINVAL; |
2197 |
return -EINVAL; |
| 2249 |
if (copy_from_user(&req, optval, sizeof(req))) |
2198 |
if (copy_from_user(&req, optval, sizeof(req))) |
| 2250 |
return -EFAULT; |
2199 |
return -EFAULT; |
| 2251 |
err = netlink_set_ring(sk, &req, |
2200 |
err = netlink_set_ring(sk, &req, false, |
| 2252 |
optname == NETLINK_TX_RING); |
2201 |
optname == NETLINK_TX_RING); |
| 2253 |
break; |
2202 |
break; |
| 2254 |
} |
2203 |
} |
|
Lines 2354-2366
Link Here
|
| 2354 |
dst_group = nlk->dst_group; |
2303 |
dst_group = nlk->dst_group; |
| 2355 |
} |
2304 |
} |
| 2356 |
|
2305 |
|
| 2357 |
if (!nlk->bound) { |
2306 |
if (!nlk->portid) { |
| 2358 |
err = netlink_autobind(sock); |
2307 |
err = netlink_autobind(sock); |
| 2359 |
if (err) |
2308 |
if (err) |
| 2360 |
goto out; |
2309 |
goto out; |
| 2361 |
} else { |
|
|
| 2362 |
/* Ensure nlk is hashed and visible. */ |
| 2363 |
smp_rmb(); |
| 2364 |
} |
2310 |
} |
| 2365 |
|
2311 |
|
| 2366 |
/* It's a really convoluted way for userland to ask for mmaped |
2312 |
/* It's a really convoluted way for userland to ask for mmaped |
|
Lines 2683-2689
Link Here
|
| 2683 |
struct sk_buff *skb = NULL; |
2629 |
struct sk_buff *skb = NULL; |
| 2684 |
struct nlmsghdr *nlh; |
2630 |
struct nlmsghdr *nlh; |
| 2685 |
int len, err = -ENOBUFS; |
2631 |
int len, err = -ENOBUFS; |
| 2686 |
int alloc_min_size; |
|
|
| 2687 |
int alloc_size; |
2632 |
int alloc_size; |
| 2688 |
|
2633 |
|
| 2689 |
mutex_lock(nlk->cb_mutex); |
2634 |
mutex_lock(nlk->cb_mutex); |
|
Lines 2692-2697
Link Here
|
| 2692 |
goto errout_skb; |
2637 |
goto errout_skb; |
| 2693 |
} |
2638 |
} |
| 2694 |
|
2639 |
|
|
|
2640 |
cb = &nlk->cb; |
| 2641 |
alloc_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE); |
| 2642 |
|
| 2695 |
if (!netlink_rx_is_mmaped(sk) && |
2643 |
if (!netlink_rx_is_mmaped(sk) && |
| 2696 |
atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) |
2644 |
atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) |
| 2697 |
goto errout_skb; |
2645 |
goto errout_skb; |
|
Lines 2701-2735
Link Here
|
| 2701 |
* to reduce number of system calls on dump operations, if user |
2649 |
* to reduce number of system calls on dump operations, if user |
| 2702 |
* ever provided a big enough buffer. |
2650 |
* ever provided a big enough buffer. |
| 2703 |
*/ |
2651 |
*/ |
| 2704 |
cb = &nlk->cb; |
2652 |
if (alloc_size < nlk->max_recvmsg_len) { |
| 2705 |
alloc_min_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE); |
2653 |
skb = netlink_alloc_skb(sk, |
| 2706 |
|
2654 |
nlk->max_recvmsg_len, |
| 2707 |
if (alloc_min_size < nlk->max_recvmsg_len) { |
2655 |
nlk->portid, |
| 2708 |
alloc_size = nlk->max_recvmsg_len; |
|
|
| 2709 |
skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, |
| 2710 |
GFP_KERNEL | |
2656 |
GFP_KERNEL | |
| 2711 |
__GFP_NOWARN | |
2657 |
__GFP_NOWARN | |
| 2712 |
__GFP_NORETRY); |
2658 |
__GFP_NORETRY); |
|
|
2659 |
/* available room should be exact amount to avoid MSG_TRUNC */ |
| 2660 |
if (skb) |
| 2661 |
skb_reserve(skb, skb_tailroom(skb) - |
| 2662 |
nlk->max_recvmsg_len); |
| 2713 |
} |
2663 |
} |
| 2714 |
if (!skb) { |
2664 |
if (!skb) |
| 2715 |
alloc_size = alloc_min_size; |
|
|
| 2716 |
skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, |
2665 |
skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, |
| 2717 |
GFP_KERNEL); |
2666 |
GFP_KERNEL); |
| 2718 |
} |
|
|
| 2719 |
if (!skb) |
2667 |
if (!skb) |
| 2720 |
goto errout_skb; |
2668 |
goto errout_skb; |
| 2721 |
|
|
|
| 2722 |
/* Trim skb to allocated size. User is expected to provide buffer as |
| 2723 |
* large as max(min_dump_alloc, 16KiB (mac_recvmsg_len capped at |
| 2724 |
* netlink_recvmsg())). dump will pack as many smaller messages as |
| 2725 |
* could fit within the allocated skb. skb is typically allocated |
| 2726 |
* with larger space than required (could be as much as near 2x the |
| 2727 |
* requested size with align to next power of 2 approach). Allowing |
| 2728 |
* dump to use the excess space makes it difficult for a user to have a |
| 2729 |
* reasonable static buffer based on the expected largest dump of a |
| 2730 |
* single netdev. The outcome is MSG_TRUNC error. |
| 2731 |
*/ |
| 2732 |
skb_reserve(skb, skb_tailroom(skb) - alloc_size); |
| 2733 |
netlink_skb_set_owner_r(skb, sk); |
2669 |
netlink_skb_set_owner_r(skb, sk); |
| 2734 |
|
2670 |
|
| 2735 |
len = cb->dump(skb, cb); |
2671 |
len = cb->dump(skb, cb); |