diff options
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 96 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 14 |
2 files changed, 50 insertions, 60 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index cd96ed3ccee4..6ef64adf7362 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -83,9 +83,9 @@ struct netlink_sock { | |||
83 | struct module *module; | 83 | struct module *module; |
84 | }; | 84 | }; |
85 | 85 | ||
86 | struct listeners_rcu_head { | 86 | struct listeners { |
87 | struct rcu_head rcu_head; | 87 | struct rcu_head rcu; |
88 | void *ptr; | 88 | unsigned long masks[0]; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | #define NETLINK_KERNEL_SOCKET 0x1 | 91 | #define NETLINK_KERNEL_SOCKET 0x1 |
@@ -119,7 +119,7 @@ struct nl_pid_hash { | |||
119 | struct netlink_table { | 119 | struct netlink_table { |
120 | struct nl_pid_hash hash; | 120 | struct nl_pid_hash hash; |
121 | struct hlist_head mc_list; | 121 | struct hlist_head mc_list; |
122 | unsigned long *listeners; | 122 | struct listeners __rcu *listeners; |
123 | unsigned int nl_nonroot; | 123 | unsigned int nl_nonroot; |
124 | unsigned int groups; | 124 | unsigned int groups; |
125 | struct mutex *cb_mutex; | 125 | struct mutex *cb_mutex; |
@@ -338,7 +338,7 @@ netlink_update_listeners(struct sock *sk) | |||
338 | if (i < NLGRPLONGS(nlk_sk(sk)->ngroups)) | 338 | if (i < NLGRPLONGS(nlk_sk(sk)->ngroups)) |
339 | mask |= nlk_sk(sk)->groups[i]; | 339 | mask |= nlk_sk(sk)->groups[i]; |
340 | } | 340 | } |
341 | tbl->listeners[i] = mask; | 341 | tbl->listeners->masks[i] = mask; |
342 | } | 342 | } |
343 | /* this function is only called with the netlink table "grabbed", which | 343 | /* this function is only called with the netlink table "grabbed", which |
344 | * makes sure updates are visible before bind or setsockopt return. */ | 344 | * makes sure updates are visible before bind or setsockopt return. */ |
@@ -936,7 +936,7 @@ EXPORT_SYMBOL(netlink_unicast); | |||
936 | int netlink_has_listeners(struct sock *sk, unsigned int group) | 936 | int netlink_has_listeners(struct sock *sk, unsigned int group) |
937 | { | 937 | { |
938 | int res = 0; | 938 | int res = 0; |
939 | unsigned long *listeners; | 939 | struct listeners *listeners; |
940 | 940 | ||
941 | BUG_ON(!netlink_is_kernel(sk)); | 941 | BUG_ON(!netlink_is_kernel(sk)); |
942 | 942 | ||
@@ -944,7 +944,7 @@ int netlink_has_listeners(struct sock *sk, unsigned int group) | |||
944 | listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); | 944 | listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); |
945 | 945 | ||
946 | if (group - 1 < nl_table[sk->sk_protocol].groups) | 946 | if (group - 1 < nl_table[sk->sk_protocol].groups) |
947 | res = test_bit(group - 1, listeners); | 947 | res = test_bit(group - 1, listeners->masks); |
948 | 948 | ||
949 | rcu_read_unlock(); | 949 | rcu_read_unlock(); |
950 | 950 | ||
@@ -1362,17 +1362,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1362 | 1362 | ||
1363 | NETLINK_CB(skb).pid = nlk->pid; | 1363 | NETLINK_CB(skb).pid = nlk->pid; |
1364 | NETLINK_CB(skb).dst_group = dst_group; | 1364 | NETLINK_CB(skb).dst_group = dst_group; |
1365 | NETLINK_CB(skb).loginuid = audit_get_loginuid(current); | ||
1366 | NETLINK_CB(skb).sessionid = audit_get_sessionid(current); | ||
1367 | security_task_getsecid(current, &(NETLINK_CB(skb).sid)); | ||
1368 | memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); | 1365 | memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); |
1369 | 1366 | ||
1370 | /* What can I do? Netlink is asynchronous, so that | ||
1371 | we will have to save current capabilities to | ||
1372 | check them, when this message will be delivered | ||
1373 | to corresponding kernel module. --ANK (980802) | ||
1374 | */ | ||
1375 | |||
1376 | err = -EFAULT; | 1367 | err = -EFAULT; |
1377 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | 1368 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { |
1378 | kfree_skb(skb); | 1369 | kfree_skb(skb); |
@@ -1407,7 +1398,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1407 | int noblock = flags&MSG_DONTWAIT; | 1398 | int noblock = flags&MSG_DONTWAIT; |
1408 | size_t copied; | 1399 | size_t copied; |
1409 | struct sk_buff *skb, *data_skb; | 1400 | struct sk_buff *skb, *data_skb; |
1410 | int err; | 1401 | int err, ret; |
1411 | 1402 | ||
1412 | if (flags&MSG_OOB) | 1403 | if (flags&MSG_OOB) |
1413 | return -EOPNOTSUPP; | 1404 | return -EOPNOTSUPP; |
@@ -1470,8 +1461,13 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1470 | 1461 | ||
1471 | skb_free_datagram(sk, skb); | 1462 | skb_free_datagram(sk, skb); |
1472 | 1463 | ||
1473 | if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) | 1464 | if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { |
1474 | netlink_dump(sk); | 1465 | ret = netlink_dump(sk); |
1466 | if (ret) { | ||
1467 | sk->sk_err = ret; | ||
1468 | sk->sk_error_report(sk); | ||
1469 | } | ||
1470 | } | ||
1475 | 1471 | ||
1476 | scm_recv(sock, msg, siocb->scm, flags); | 1472 | scm_recv(sock, msg, siocb->scm, flags); |
1477 | out: | 1473 | out: |
@@ -1498,7 +1494,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, | |||
1498 | struct socket *sock; | 1494 | struct socket *sock; |
1499 | struct sock *sk; | 1495 | struct sock *sk; |
1500 | struct netlink_sock *nlk; | 1496 | struct netlink_sock *nlk; |
1501 | unsigned long *listeners = NULL; | 1497 | struct listeners *listeners = NULL; |
1502 | 1498 | ||
1503 | BUG_ON(!nl_table); | 1499 | BUG_ON(!nl_table); |
1504 | 1500 | ||
@@ -1523,8 +1519,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, | |||
1523 | if (groups < 32) | 1519 | if (groups < 32) |
1524 | groups = 32; | 1520 | groups = 32; |
1525 | 1521 | ||
1526 | listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head), | 1522 | listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); |
1527 | GFP_KERNEL); | ||
1528 | if (!listeners) | 1523 | if (!listeners) |
1529 | goto out_sock_release; | 1524 | goto out_sock_release; |
1530 | 1525 | ||
@@ -1541,7 +1536,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, | |||
1541 | netlink_table_grab(); | 1536 | netlink_table_grab(); |
1542 | if (!nl_table[unit].registered) { | 1537 | if (!nl_table[unit].registered) { |
1543 | nl_table[unit].groups = groups; | 1538 | nl_table[unit].groups = groups; |
1544 | nl_table[unit].listeners = listeners; | 1539 | rcu_assign_pointer(nl_table[unit].listeners, listeners); |
1545 | nl_table[unit].cb_mutex = cb_mutex; | 1540 | nl_table[unit].cb_mutex = cb_mutex; |
1546 | nl_table[unit].module = module; | 1541 | nl_table[unit].module = module; |
1547 | nl_table[unit].registered = 1; | 1542 | nl_table[unit].registered = 1; |
@@ -1571,44 +1566,23 @@ netlink_kernel_release(struct sock *sk) | |||
1571 | } | 1566 | } |
1572 | EXPORT_SYMBOL(netlink_kernel_release); | 1567 | EXPORT_SYMBOL(netlink_kernel_release); |
1573 | 1568 | ||
1574 | |||
1575 | static void netlink_free_old_listeners(struct rcu_head *rcu_head) | ||
1576 | { | ||
1577 | struct listeners_rcu_head *lrh; | ||
1578 | |||
1579 | lrh = container_of(rcu_head, struct listeners_rcu_head, rcu_head); | ||
1580 | kfree(lrh->ptr); | ||
1581 | } | ||
1582 | |||
1583 | int __netlink_change_ngroups(struct sock *sk, unsigned int groups) | 1569 | int __netlink_change_ngroups(struct sock *sk, unsigned int groups) |
1584 | { | 1570 | { |
1585 | unsigned long *listeners, *old = NULL; | 1571 | struct listeners *new, *old; |
1586 | struct listeners_rcu_head *old_rcu_head; | ||
1587 | struct netlink_table *tbl = &nl_table[sk->sk_protocol]; | 1572 | struct netlink_table *tbl = &nl_table[sk->sk_protocol]; |
1588 | 1573 | ||
1589 | if (groups < 32) | 1574 | if (groups < 32) |
1590 | groups = 32; | 1575 | groups = 32; |
1591 | 1576 | ||
1592 | if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { | 1577 | if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { |
1593 | listeners = kzalloc(NLGRPSZ(groups) + | 1578 | new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC); |
1594 | sizeof(struct listeners_rcu_head), | 1579 | if (!new) |
1595 | GFP_ATOMIC); | ||
1596 | if (!listeners) | ||
1597 | return -ENOMEM; | 1580 | return -ENOMEM; |
1598 | old = tbl->listeners; | 1581 | old = rcu_dereference_raw(tbl->listeners); |
1599 | memcpy(listeners, old, NLGRPSZ(tbl->groups)); | 1582 | memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups)); |
1600 | rcu_assign_pointer(tbl->listeners, listeners); | 1583 | rcu_assign_pointer(tbl->listeners, new); |
1601 | /* | 1584 | |
1602 | * Free the old memory after an RCU grace period so we | 1585 | kfree_rcu(old, rcu); |
1603 | * don't leak it. We use call_rcu() here in order to be | ||
1604 | * able to call this function from atomic contexts. The | ||
1605 | * allocation of this memory will have reserved enough | ||
1606 | * space for struct listeners_rcu_head at the end. | ||
1607 | */ | ||
1608 | old_rcu_head = (void *)(tbl->listeners + | ||
1609 | NLGRPLONGS(tbl->groups)); | ||
1610 | old_rcu_head->ptr = old; | ||
1611 | call_rcu(&old_rcu_head->rcu_head, netlink_free_old_listeners); | ||
1612 | } | 1586 | } |
1613 | tbl->groups = groups; | 1587 | tbl->groups = groups; |
1614 | 1588 | ||
@@ -1752,6 +1726,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | |||
1752 | struct netlink_callback *cb; | 1726 | struct netlink_callback *cb; |
1753 | struct sock *sk; | 1727 | struct sock *sk; |
1754 | struct netlink_sock *nlk; | 1728 | struct netlink_sock *nlk; |
1729 | int ret; | ||
1755 | 1730 | ||
1756 | cb = kzalloc(sizeof(*cb), GFP_KERNEL); | 1731 | cb = kzalloc(sizeof(*cb), GFP_KERNEL); |
1757 | if (cb == NULL) | 1732 | if (cb == NULL) |
@@ -1780,9 +1755,13 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | |||
1780 | nlk->cb = cb; | 1755 | nlk->cb = cb; |
1781 | mutex_unlock(nlk->cb_mutex); | 1756 | mutex_unlock(nlk->cb_mutex); |
1782 | 1757 | ||
1783 | netlink_dump(sk); | 1758 | ret = netlink_dump(sk); |
1759 | |||
1784 | sock_put(sk); | 1760 | sock_put(sk); |
1785 | 1761 | ||
1762 | if (ret) | ||
1763 | return ret; | ||
1764 | |||
1786 | /* We successfully started a dump, by returning -EINTR we | 1765 | /* We successfully started a dump, by returning -EINTR we |
1787 | * signal not to send ACK even if it was requested. | 1766 | * signal not to send ACK even if it was requested. |
1788 | */ | 1767 | */ |
@@ -2006,7 +1985,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
2006 | struct sock *s = v; | 1985 | struct sock *s = v; |
2007 | struct netlink_sock *nlk = nlk_sk(s); | 1986 | struct netlink_sock *nlk = nlk_sk(s); |
2008 | 1987 | ||
2009 | seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %-8d %-8d %-8lu\n", | 1988 | seq_printf(seq, "%pK %-3d %-6d %08x %-8d %-8d %pK %-8d %-8d %-8lu\n", |
2010 | s, | 1989 | s, |
2011 | s->sk_protocol, | 1990 | s->sk_protocol, |
2012 | nlk->pid, | 1991 | nlk->pid, |
@@ -2104,18 +2083,17 @@ static void __net_exit netlink_net_exit(struct net *net) | |||
2104 | 2083 | ||
2105 | static void __init netlink_add_usersock_entry(void) | 2084 | static void __init netlink_add_usersock_entry(void) |
2106 | { | 2085 | { |
2107 | unsigned long *listeners; | 2086 | struct listeners *listeners; |
2108 | int groups = 32; | 2087 | int groups = 32; |
2109 | 2088 | ||
2110 | listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head), | 2089 | listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); |
2111 | GFP_KERNEL); | ||
2112 | if (!listeners) | 2090 | if (!listeners) |
2113 | panic("netlink_add_usersock_entry: Cannot allocate listneres\n"); | 2091 | panic("netlink_add_usersock_entry: Cannot allocate listeners\n"); |
2114 | 2092 | ||
2115 | netlink_table_grab(); | 2093 | netlink_table_grab(); |
2116 | 2094 | ||
2117 | nl_table[NETLINK_USERSOCK].groups = groups; | 2095 | nl_table[NETLINK_USERSOCK].groups = groups; |
2118 | nl_table[NETLINK_USERSOCK].listeners = listeners; | 2096 | rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners); |
2119 | nl_table[NETLINK_USERSOCK].module = THIS_MODULE; | 2097 | nl_table[NETLINK_USERSOCK].module = THIS_MODULE; |
2120 | nl_table[NETLINK_USERSOCK].registered = 1; | 2098 | nl_table[NETLINK_USERSOCK].registered = 1; |
2121 | 2099 | ||
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 26ed3e8587c2..1781d99145e2 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -547,8 +547,20 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
547 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; | 547 | info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; |
548 | info.attrs = family->attrbuf; | 548 | info.attrs = family->attrbuf; |
549 | genl_info_net_set(&info, net); | 549 | genl_info_net_set(&info, net); |
550 | memset(&info.user_ptr, 0, sizeof(info.user_ptr)); | ||
550 | 551 | ||
551 | return ops->doit(skb, &info); | 552 | if (family->pre_doit) { |
553 | err = family->pre_doit(ops, skb, &info); | ||
554 | if (err) | ||
555 | return err; | ||
556 | } | ||
557 | |||
558 | err = ops->doit(skb, &info); | ||
559 | |||
560 | if (family->post_doit) | ||
561 | family->post_doit(ops, skb, &info); | ||
562 | |||
563 | return err; | ||
552 | } | 564 | } |
553 | 565 | ||
554 | static void genl_rcv(struct sk_buff *skb) | 566 | static void genl_rcv(struct sk_buff *skb) |