diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2007-09-12 07:05:38 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:49:09 -0400 |
commit | b4b510290b056b86611757ce1175a230f1080f53 (patch) | |
tree | 7bd1d45855ac7457be6d50338c60751f19e436d9 /net/netlink/af_netlink.c | |
parent | e9dc86534051b78e41e5b746cccc291b57a3a311 (diff) |
[NET]: Support multiple network namespaces with netlink
Each netlink socket will live in exactly one network namespace,
this includes the controlling kernel sockets.
This patch updates all of the existing netlink protocols
to only support the initial network namespace. Request
by clients in other namespaces will get -ECONREFUSED.
As they would if the kernel did not have the support for
that netlink protocol compiled in.
As each netlink protocol is updated to be multiple network
namespace safe it can register multiple kernel sockets
to acquire a presence in the rest of the network namespaces.
The implementation in af_netlink is a simple filter implementation
at hash table insertion and hash table look up time.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r-- | net/netlink/af_netlink.c | 104 |
1 files changed, 78 insertions, 26 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 406a493300d8..3029f865cd61 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -211,7 +211,7 @@ netlink_unlock_table(void) | |||
211 | wake_up(&nl_table_wait); | 211 | wake_up(&nl_table_wait); |
212 | } | 212 | } |
213 | 213 | ||
214 | static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) | 214 | static __inline__ struct sock *netlink_lookup(struct net *net, int protocol, u32 pid) |
215 | { | 215 | { |
216 | struct nl_pid_hash *hash = &nl_table[protocol].hash; | 216 | struct nl_pid_hash *hash = &nl_table[protocol].hash; |
217 | struct hlist_head *head; | 217 | struct hlist_head *head; |
@@ -221,7 +221,7 @@ static __inline__ struct sock *netlink_lookup(int protocol, u32 pid) | |||
221 | read_lock(&nl_table_lock); | 221 | read_lock(&nl_table_lock); |
222 | head = nl_pid_hashfn(hash, pid); | 222 | head = nl_pid_hashfn(hash, pid); |
223 | sk_for_each(sk, node, head) { | 223 | sk_for_each(sk, node, head) { |
224 | if (nlk_sk(sk)->pid == pid) { | 224 | if ((sk->sk_net == net) && (nlk_sk(sk)->pid == pid)) { |
225 | sock_hold(sk); | 225 | sock_hold(sk); |
226 | goto found; | 226 | goto found; |
227 | } | 227 | } |
@@ -328,7 +328,7 @@ netlink_update_listeners(struct sock *sk) | |||
328 | * makes sure updates are visible before bind or setsockopt return. */ | 328 | * makes sure updates are visible before bind or setsockopt return. */ |
329 | } | 329 | } |
330 | 330 | ||
331 | static int netlink_insert(struct sock *sk, u32 pid) | 331 | static int netlink_insert(struct sock *sk, struct net *net, u32 pid) |
332 | { | 332 | { |
333 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; | 333 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; |
334 | struct hlist_head *head; | 334 | struct hlist_head *head; |
@@ -341,7 +341,7 @@ static int netlink_insert(struct sock *sk, u32 pid) | |||
341 | head = nl_pid_hashfn(hash, pid); | 341 | head = nl_pid_hashfn(hash, pid); |
342 | len = 0; | 342 | len = 0; |
343 | sk_for_each(osk, node, head) { | 343 | sk_for_each(osk, node, head) { |
344 | if (nlk_sk(osk)->pid == pid) | 344 | if ((osk->sk_net == net) && (nlk_sk(osk)->pid == pid)) |
345 | break; | 345 | break; |
346 | len++; | 346 | len++; |
347 | } | 347 | } |
@@ -419,9 +419,6 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol) | |||
419 | struct netlink_sock *nlk; | 419 | struct netlink_sock *nlk; |
420 | int err = 0; | 420 | int err = 0; |
421 | 421 | ||
422 | if (net != &init_net) | ||
423 | return -EAFNOSUPPORT; | ||
424 | |||
425 | sock->state = SS_UNCONNECTED; | 422 | sock->state = SS_UNCONNECTED; |
426 | 423 | ||
427 | if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) | 424 | if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) |
@@ -481,6 +478,7 @@ static int netlink_release(struct socket *sock) | |||
481 | 478 | ||
482 | if (nlk->pid && !nlk->subscriptions) { | 479 | if (nlk->pid && !nlk->subscriptions) { |
483 | struct netlink_notify n = { | 480 | struct netlink_notify n = { |
481 | .net = sk->sk_net, | ||
484 | .protocol = sk->sk_protocol, | 482 | .protocol = sk->sk_protocol, |
485 | .pid = nlk->pid, | 483 | .pid = nlk->pid, |
486 | }; | 484 | }; |
@@ -509,6 +507,7 @@ static int netlink_release(struct socket *sock) | |||
509 | static int netlink_autobind(struct socket *sock) | 507 | static int netlink_autobind(struct socket *sock) |
510 | { | 508 | { |
511 | struct sock *sk = sock->sk; | 509 | struct sock *sk = sock->sk; |
510 | struct net *net = sk->sk_net; | ||
512 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; | 511 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; |
513 | struct hlist_head *head; | 512 | struct hlist_head *head; |
514 | struct sock *osk; | 513 | struct sock *osk; |
@@ -522,6 +521,8 @@ retry: | |||
522 | netlink_table_grab(); | 521 | netlink_table_grab(); |
523 | head = nl_pid_hashfn(hash, pid); | 522 | head = nl_pid_hashfn(hash, pid); |
524 | sk_for_each(osk, node, head) { | 523 | sk_for_each(osk, node, head) { |
524 | if ((osk->sk_net != net)) | ||
525 | continue; | ||
525 | if (nlk_sk(osk)->pid == pid) { | 526 | if (nlk_sk(osk)->pid == pid) { |
526 | /* Bind collision, search negative pid values. */ | 527 | /* Bind collision, search negative pid values. */ |
527 | pid = rover--; | 528 | pid = rover--; |
@@ -533,7 +534,7 @@ retry: | |||
533 | } | 534 | } |
534 | netlink_table_ungrab(); | 535 | netlink_table_ungrab(); |
535 | 536 | ||
536 | err = netlink_insert(sk, pid); | 537 | err = netlink_insert(sk, net, pid); |
537 | if (err == -EADDRINUSE) | 538 | if (err == -EADDRINUSE) |
538 | goto retry; | 539 | goto retry; |
539 | 540 | ||
@@ -598,6 +599,7 @@ static int netlink_realloc_groups(struct sock *sk) | |||
598 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | 599 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) |
599 | { | 600 | { |
600 | struct sock *sk = sock->sk; | 601 | struct sock *sk = sock->sk; |
602 | struct net *net = sk->sk_net; | ||
601 | struct netlink_sock *nlk = nlk_sk(sk); | 603 | struct netlink_sock *nlk = nlk_sk(sk); |
602 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; | 604 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
603 | int err; | 605 | int err; |
@@ -619,7 +621,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len | |||
619 | return -EINVAL; | 621 | return -EINVAL; |
620 | } else { | 622 | } else { |
621 | err = nladdr->nl_pid ? | 623 | err = nladdr->nl_pid ? |
622 | netlink_insert(sk, nladdr->nl_pid) : | 624 | netlink_insert(sk, net, nladdr->nl_pid) : |
623 | netlink_autobind(sock); | 625 | netlink_autobind(sock); |
624 | if (err) | 626 | if (err) |
625 | return err; | 627 | return err; |
@@ -703,10 +705,12 @@ static void netlink_overrun(struct sock *sk) | |||
703 | static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) | 705 | static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) |
704 | { | 706 | { |
705 | int protocol = ssk->sk_protocol; | 707 | int protocol = ssk->sk_protocol; |
708 | struct net *net; | ||
706 | struct sock *sock; | 709 | struct sock *sock; |
707 | struct netlink_sock *nlk; | 710 | struct netlink_sock *nlk; |
708 | 711 | ||
709 | sock = netlink_lookup(protocol, pid); | 712 | net = ssk->sk_net; |
713 | sock = netlink_lookup(net, protocol, pid); | ||
710 | if (!sock) | 714 | if (!sock) |
711 | return ERR_PTR(-ECONNREFUSED); | 715 | return ERR_PTR(-ECONNREFUSED); |
712 | 716 | ||
@@ -887,6 +891,7 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff | |||
887 | 891 | ||
888 | struct netlink_broadcast_data { | 892 | struct netlink_broadcast_data { |
889 | struct sock *exclude_sk; | 893 | struct sock *exclude_sk; |
894 | struct net *net; | ||
890 | u32 pid; | 895 | u32 pid; |
891 | u32 group; | 896 | u32 group; |
892 | int failure; | 897 | int failure; |
@@ -909,6 +914,9 @@ static inline int do_one_broadcast(struct sock *sk, | |||
909 | !test_bit(p->group - 1, nlk->groups)) | 914 | !test_bit(p->group - 1, nlk->groups)) |
910 | goto out; | 915 | goto out; |
911 | 916 | ||
917 | if ((sk->sk_net != p->net)) | ||
918 | goto out; | ||
919 | |||
912 | if (p->failure) { | 920 | if (p->failure) { |
913 | netlink_overrun(sk); | 921 | netlink_overrun(sk); |
914 | goto out; | 922 | goto out; |
@@ -947,6 +955,7 @@ out: | |||
947 | int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | 955 | int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, |
948 | u32 group, gfp_t allocation) | 956 | u32 group, gfp_t allocation) |
949 | { | 957 | { |
958 | struct net *net = ssk->sk_net; | ||
950 | struct netlink_broadcast_data info; | 959 | struct netlink_broadcast_data info; |
951 | struct hlist_node *node; | 960 | struct hlist_node *node; |
952 | struct sock *sk; | 961 | struct sock *sk; |
@@ -954,6 +963,7 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | |||
954 | skb = netlink_trim(skb, allocation); | 963 | skb = netlink_trim(skb, allocation); |
955 | 964 | ||
956 | info.exclude_sk = ssk; | 965 | info.exclude_sk = ssk; |
966 | info.net = net; | ||
957 | info.pid = pid; | 967 | info.pid = pid; |
958 | info.group = group; | 968 | info.group = group; |
959 | info.failure = 0; | 969 | info.failure = 0; |
@@ -1002,6 +1012,9 @@ static inline int do_one_set_err(struct sock *sk, | |||
1002 | if (sk == p->exclude_sk) | 1012 | if (sk == p->exclude_sk) |
1003 | goto out; | 1013 | goto out; |
1004 | 1014 | ||
1015 | if (sk->sk_net != p->exclude_sk->sk_net) | ||
1016 | goto out; | ||
1017 | |||
1005 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || | 1018 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || |
1006 | !test_bit(p->group - 1, nlk->groups)) | 1019 | !test_bit(p->group - 1, nlk->groups)) |
1007 | goto out; | 1020 | goto out; |
@@ -1304,7 +1317,7 @@ static void netlink_data_ready(struct sock *sk, int len) | |||
1304 | */ | 1317 | */ |
1305 | 1318 | ||
1306 | struct sock * | 1319 | struct sock * |
1307 | netlink_kernel_create(int unit, unsigned int groups, | 1320 | netlink_kernel_create(struct net *net, int unit, unsigned int groups, |
1308 | void (*input)(struct sock *sk, int len), | 1321 | void (*input)(struct sock *sk, int len), |
1309 | struct mutex *cb_mutex, struct module *module) | 1322 | struct mutex *cb_mutex, struct module *module) |
1310 | { | 1323 | { |
@@ -1321,7 +1334,7 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1321 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) | 1334 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) |
1322 | return NULL; | 1335 | return NULL; |
1323 | 1336 | ||
1324 | if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0) | 1337 | if (__netlink_create(net, sock, cb_mutex, unit) < 0) |
1325 | goto out_sock_release; | 1338 | goto out_sock_release; |
1326 | 1339 | ||
1327 | if (groups < 32) | 1340 | if (groups < 32) |
@@ -1336,18 +1349,20 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1336 | if (input) | 1349 | if (input) |
1337 | nlk_sk(sk)->data_ready = input; | 1350 | nlk_sk(sk)->data_ready = input; |
1338 | 1351 | ||
1339 | if (netlink_insert(sk, 0)) | 1352 | if (netlink_insert(sk, net, 0)) |
1340 | goto out_sock_release; | 1353 | goto out_sock_release; |
1341 | 1354 | ||
1342 | nlk = nlk_sk(sk); | 1355 | nlk = nlk_sk(sk); |
1343 | nlk->flags |= NETLINK_KERNEL_SOCKET; | 1356 | nlk->flags |= NETLINK_KERNEL_SOCKET; |
1344 | 1357 | ||
1345 | netlink_table_grab(); | 1358 | netlink_table_grab(); |
1346 | nl_table[unit].groups = groups; | 1359 | if (!nl_table[unit].registered) { |
1347 | nl_table[unit].listeners = listeners; | 1360 | nl_table[unit].groups = groups; |
1348 | nl_table[unit].cb_mutex = cb_mutex; | 1361 | nl_table[unit].listeners = listeners; |
1349 | nl_table[unit].module = module; | 1362 | nl_table[unit].cb_mutex = cb_mutex; |
1350 | nl_table[unit].registered = 1; | 1363 | nl_table[unit].module = module; |
1364 | nl_table[unit].registered = 1; | ||
1365 | } | ||
1351 | netlink_table_ungrab(); | 1366 | netlink_table_ungrab(); |
1352 | 1367 | ||
1353 | return sk; | 1368 | return sk; |
@@ -1513,7 +1528,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | |||
1513 | atomic_inc(&skb->users); | 1528 | atomic_inc(&skb->users); |
1514 | cb->skb = skb; | 1529 | cb->skb = skb; |
1515 | 1530 | ||
1516 | sk = netlink_lookup(ssk->sk_protocol, NETLINK_CB(skb).pid); | 1531 | sk = netlink_lookup(ssk->sk_net, ssk->sk_protocol, NETLINK_CB(skb).pid); |
1517 | if (sk == NULL) { | 1532 | if (sk == NULL) { |
1518 | netlink_destroy_callback(cb); | 1533 | netlink_destroy_callback(cb); |
1519 | return -ECONNREFUSED; | 1534 | return -ECONNREFUSED; |
@@ -1555,7 +1570,8 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
1555 | if (!skb) { | 1570 | if (!skb) { |
1556 | struct sock *sk; | 1571 | struct sock *sk; |
1557 | 1572 | ||
1558 | sk = netlink_lookup(in_skb->sk->sk_protocol, | 1573 | sk = netlink_lookup(in_skb->sk->sk_net, |
1574 | in_skb->sk->sk_protocol, | ||
1559 | NETLINK_CB(in_skb).pid); | 1575 | NETLINK_CB(in_skb).pid); |
1560 | if (sk) { | 1576 | if (sk) { |
1561 | sk->sk_err = ENOBUFS; | 1577 | sk->sk_err = ENOBUFS; |
@@ -1706,6 +1722,7 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, | |||
1706 | 1722 | ||
1707 | #ifdef CONFIG_PROC_FS | 1723 | #ifdef CONFIG_PROC_FS |
1708 | struct nl_seq_iter { | 1724 | struct nl_seq_iter { |
1725 | struct net *net; | ||
1709 | int link; | 1726 | int link; |
1710 | int hash_idx; | 1727 | int hash_idx; |
1711 | }; | 1728 | }; |
@@ -1723,6 +1740,8 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) | |||
1723 | 1740 | ||
1724 | for (j = 0; j <= hash->mask; j++) { | 1741 | for (j = 0; j <= hash->mask; j++) { |
1725 | sk_for_each(s, node, &hash->table[j]) { | 1742 | sk_for_each(s, node, &hash->table[j]) { |
1743 | if (iter->net != s->sk_net) | ||
1744 | continue; | ||
1726 | if (off == pos) { | 1745 | if (off == pos) { |
1727 | iter->link = i; | 1746 | iter->link = i; |
1728 | iter->hash_idx = j; | 1747 | iter->hash_idx = j; |
@@ -1752,11 +1771,14 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1752 | if (v == SEQ_START_TOKEN) | 1771 | if (v == SEQ_START_TOKEN) |
1753 | return netlink_seq_socket_idx(seq, 0); | 1772 | return netlink_seq_socket_idx(seq, 0); |
1754 | 1773 | ||
1755 | s = sk_next(v); | 1774 | iter = seq->private; |
1775 | s = v; | ||
1776 | do { | ||
1777 | s = sk_next(s); | ||
1778 | } while (s && (iter->net != s->sk_net)); | ||
1756 | if (s) | 1779 | if (s) |
1757 | return s; | 1780 | return s; |
1758 | 1781 | ||
1759 | iter = seq->private; | ||
1760 | i = iter->link; | 1782 | i = iter->link; |
1761 | j = iter->hash_idx + 1; | 1783 | j = iter->hash_idx + 1; |
1762 | 1784 | ||
@@ -1765,6 +1787,8 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1765 | 1787 | ||
1766 | for (; j <= hash->mask; j++) { | 1788 | for (; j <= hash->mask; j++) { |
1767 | s = sk_head(&hash->table[j]); | 1789 | s = sk_head(&hash->table[j]); |
1790 | while (s && (iter->net != s->sk_net)) | ||
1791 | s = sk_next(s); | ||
1768 | if (s) { | 1792 | if (s) { |
1769 | iter->link = i; | 1793 | iter->link = i; |
1770 | iter->hash_idx = j; | 1794 | iter->hash_idx = j; |
@@ -1835,15 +1859,24 @@ static int netlink_seq_open(struct inode *inode, struct file *file) | |||
1835 | 1859 | ||
1836 | seq = file->private_data; | 1860 | seq = file->private_data; |
1837 | seq->private = iter; | 1861 | seq->private = iter; |
1862 | iter->net = get_net(PROC_NET(inode)); | ||
1838 | return 0; | 1863 | return 0; |
1839 | } | 1864 | } |
1840 | 1865 | ||
1866 | static int netlink_seq_release(struct inode *inode, struct file *file) | ||
1867 | { | ||
1868 | struct seq_file *seq = file->private_data; | ||
1869 | struct nl_seq_iter *iter = seq->private; | ||
1870 | put_net(iter->net); | ||
1871 | return seq_release_private(inode, file); | ||
1872 | } | ||
1873 | |||
1841 | static const struct file_operations netlink_seq_fops = { | 1874 | static const struct file_operations netlink_seq_fops = { |
1842 | .owner = THIS_MODULE, | 1875 | .owner = THIS_MODULE, |
1843 | .open = netlink_seq_open, | 1876 | .open = netlink_seq_open, |
1844 | .read = seq_read, | 1877 | .read = seq_read, |
1845 | .llseek = seq_lseek, | 1878 | .llseek = seq_lseek, |
1846 | .release = seq_release_private, | 1879 | .release = netlink_seq_release, |
1847 | }; | 1880 | }; |
1848 | 1881 | ||
1849 | #endif | 1882 | #endif |
@@ -1885,6 +1918,27 @@ static struct net_proto_family netlink_family_ops = { | |||
1885 | .owner = THIS_MODULE, /* for consistency 8) */ | 1918 | .owner = THIS_MODULE, /* for consistency 8) */ |
1886 | }; | 1919 | }; |
1887 | 1920 | ||
1921 | static int netlink_net_init(struct net *net) | ||
1922 | { | ||
1923 | #ifdef CONFIG_PROC_FS | ||
1924 | if (!proc_net_fops_create(net, "netlink", 0, &netlink_seq_fops)) | ||
1925 | return -ENOMEM; | ||
1926 | #endif | ||
1927 | return 0; | ||
1928 | } | ||
1929 | |||
1930 | static void netlink_net_exit(struct net *net) | ||
1931 | { | ||
1932 | #ifdef CONFIG_PROC_FS | ||
1933 | proc_net_remove(net, "netlink"); | ||
1934 | #endif | ||
1935 | } | ||
1936 | |||
1937 | static struct pernet_operations netlink_net_ops = { | ||
1938 | .init = netlink_net_init, | ||
1939 | .exit = netlink_net_exit, | ||
1940 | }; | ||
1941 | |||
1888 | static int __init netlink_proto_init(void) | 1942 | static int __init netlink_proto_init(void) |
1889 | { | 1943 | { |
1890 | struct sk_buff *dummy_skb; | 1944 | struct sk_buff *dummy_skb; |
@@ -1930,9 +1984,7 @@ static int __init netlink_proto_init(void) | |||
1930 | } | 1984 | } |
1931 | 1985 | ||
1932 | sock_register(&netlink_family_ops); | 1986 | sock_register(&netlink_family_ops); |
1933 | #ifdef CONFIG_PROC_FS | 1987 | register_pernet_subsys(&netlink_net_ops); |
1934 | proc_net_fops_create(&init_net, "netlink", 0, &netlink_seq_fops); | ||
1935 | #endif | ||
1936 | /* The netlink device handler may be needed early. */ | 1988 | /* The netlink device handler may be needed early. */ |
1937 | rtnetlink_init(); | 1989 | rtnetlink_init(); |
1938 | out: | 1990 | out: |