aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-12-23 15:00:06 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-27 03:07:50 -0500
commit023e2cfa36c31b0ad28c159a1bb0d61ff57334c8 (patch)
treefb696a81e6c2246cec25cfa35741de31c090ed7a /net/netlink
parenteb69c5bf8273edbe1c5c748fa299b5e5a08f35d6 (diff)
netlink/genetlink: pass network namespace to bind/unbind
Netlink families can exist in multiple namespaces, and for the most part multicast subscriptions are per network namespace. Thus it only makes sense to have bind/unbind notifications per network namespace. To achieve this, pass the network namespace of a given client socket to the bind/unbind functions. Also do this in generic netlink, and there also make sure that any bind for multicast groups that only exist in init_net is rejected. This isn't really a problem if it is accepted since a client in a different namespace will never receive any notifications from such a group, but it can confuse the family if not rejected (it's also possible to silently (without telling the family) accept it, but it would also have to be ignored on unbind so families that take any kind of action on bind/unbind won't do unnecessary work for invalid clients like that. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r--net/netlink/af_netlink.c21
-rw-r--r--net/netlink/af_netlink.h8
-rw-r--r--net/netlink/genetlink.c12
3 files changed, 22 insertions, 19 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index f29b63fad932..84ea76ca3f1f 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1141,8 +1141,8 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
1141 struct module *module = NULL; 1141 struct module *module = NULL;
1142 struct mutex *cb_mutex; 1142 struct mutex *cb_mutex;
1143 struct netlink_sock *nlk; 1143 struct netlink_sock *nlk;
1144 int (*bind)(int group); 1144 int (*bind)(struct net *net, int group);
1145 void (*unbind)(int group); 1145 void (*unbind)(struct net *net, int group);
1146 int err = 0; 1146 int err = 0;
1147 1147
1148 sock->state = SS_UNCONNECTED; 1148 sock->state = SS_UNCONNECTED;
@@ -1251,7 +1251,7 @@ static int netlink_release(struct socket *sock)
1251 1251
1252 for (i = 0; i < nlk->ngroups; i++) 1252 for (i = 0; i < nlk->ngroups; i++)
1253 if (test_bit(i, nlk->groups)) 1253 if (test_bit(i, nlk->groups))
1254 nlk->netlink_unbind(i + 1); 1254 nlk->netlink_unbind(sock_net(sk), i + 1);
1255 } 1255 }
1256 kfree(nlk->groups); 1256 kfree(nlk->groups);
1257 nlk->groups = NULL; 1257 nlk->groups = NULL;
@@ -1418,8 +1418,9 @@ static int netlink_realloc_groups(struct sock *sk)
1418} 1418}
1419 1419
1420static void netlink_undo_bind(int group, long unsigned int groups, 1420static void netlink_undo_bind(int group, long unsigned int groups,
1421 struct netlink_sock *nlk) 1421 struct sock *sk)
1422{ 1422{
1423 struct netlink_sock *nlk = nlk_sk(sk);
1423 int undo; 1424 int undo;
1424 1425
1425 if (!nlk->netlink_unbind) 1426 if (!nlk->netlink_unbind)
@@ -1427,7 +1428,7 @@ static void netlink_undo_bind(int group, long unsigned int groups,
1427 1428
1428 for (undo = 0; undo < group; undo++) 1429 for (undo = 0; undo < group; undo++)
1429 if (test_bit(undo, &groups)) 1430 if (test_bit(undo, &groups))
1430 nlk->netlink_unbind(undo); 1431 nlk->netlink_unbind(sock_net(sk), undo);
1431} 1432}
1432 1433
1433static int netlink_bind(struct socket *sock, struct sockaddr *addr, 1434static int netlink_bind(struct socket *sock, struct sockaddr *addr,
@@ -1465,10 +1466,10 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
1465 for (group = 0; group < nlk->ngroups; group++) { 1466 for (group = 0; group < nlk->ngroups; group++) {
1466 if (!test_bit(group, &groups)) 1467 if (!test_bit(group, &groups))
1467 continue; 1468 continue;
1468 err = nlk->netlink_bind(group); 1469 err = nlk->netlink_bind(net, group);
1469 if (!err) 1470 if (!err)
1470 continue; 1471 continue;
1471 netlink_undo_bind(group, groups, nlk); 1472 netlink_undo_bind(group, groups, sk);
1472 return err; 1473 return err;
1473 } 1474 }
1474 } 1475 }
@@ -1478,7 +1479,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
1478 netlink_insert(sk, net, nladdr->nl_pid) : 1479 netlink_insert(sk, net, nladdr->nl_pid) :
1479 netlink_autobind(sock); 1480 netlink_autobind(sock);
1480 if (err) { 1481 if (err) {
1481 netlink_undo_bind(nlk->ngroups, groups, nlk); 1482 netlink_undo_bind(nlk->ngroups, groups, sk);
1482 return err; 1483 return err;
1483 } 1484 }
1484 } 1485 }
@@ -2129,7 +2130,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
2129 if (!val || val - 1 >= nlk->ngroups) 2130 if (!val || val - 1 >= nlk->ngroups)
2130 return -EINVAL; 2131 return -EINVAL;
2131 if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) { 2132 if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) {
2132 err = nlk->netlink_bind(val); 2133 err = nlk->netlink_bind(sock_net(sk), val);
2133 if (err) 2134 if (err)
2134 return err; 2135 return err;
2135 } 2136 }
@@ -2138,7 +2139,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
2138 optname == NETLINK_ADD_MEMBERSHIP); 2139 optname == NETLINK_ADD_MEMBERSHIP);
2139 netlink_table_ungrab(); 2140 netlink_table_ungrab();
2140 if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind) 2141 if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind)
2141 nlk->netlink_unbind(val); 2142 nlk->netlink_unbind(sock_net(sk), val);
2142 2143
2143 err = 0; 2144 err = 0;
2144 break; 2145 break;
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
index b20a1731759b..f123a88496f8 100644
--- a/net/netlink/af_netlink.h
+++ b/net/netlink/af_netlink.h
@@ -39,8 +39,8 @@ struct netlink_sock {
39 struct mutex *cb_mutex; 39 struct mutex *cb_mutex;
40 struct mutex cb_def_mutex; 40 struct mutex cb_def_mutex;
41 void (*netlink_rcv)(struct sk_buff *skb); 41 void (*netlink_rcv)(struct sk_buff *skb);
42 int (*netlink_bind)(int group); 42 int (*netlink_bind)(struct net *net, int group);
43 void (*netlink_unbind)(int group); 43 void (*netlink_unbind)(struct net *net, int group);
44 struct module *module; 44 struct module *module;
45#ifdef CONFIG_NETLINK_MMAP 45#ifdef CONFIG_NETLINK_MMAP
46 struct mutex pg_vec_lock; 46 struct mutex pg_vec_lock;
@@ -65,8 +65,8 @@ struct netlink_table {
65 unsigned int groups; 65 unsigned int groups;
66 struct mutex *cb_mutex; 66 struct mutex *cb_mutex;
67 struct module *module; 67 struct module *module;
68 int (*bind)(int group); 68 int (*bind)(struct net *net, int group);
69 void (*unbind)(int group); 69 void (*unbind)(struct net *net, int group);
70 bool (*compare)(struct net *net, struct sock *sock); 70 bool (*compare)(struct net *net, struct sock *sock);
71 int registered; 71 int registered;
72}; 72};
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 05bf40bbd189..91566ed36c43 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -983,7 +983,7 @@ static struct genl_multicast_group genl_ctrl_groups[] = {
983 { .name = "notify", }, 983 { .name = "notify", },
984}; 984};
985 985
986static int genl_bind(int group) 986static int genl_bind(struct net *net, int group)
987{ 987{
988 int i, err; 988 int i, err;
989 bool found = false; 989 bool found = false;
@@ -997,8 +997,10 @@ static int genl_bind(int group)
997 group < f->mcgrp_offset + f->n_mcgrps) { 997 group < f->mcgrp_offset + f->n_mcgrps) {
998 int fam_grp = group - f->mcgrp_offset; 998 int fam_grp = group - f->mcgrp_offset;
999 999
1000 if (f->mcast_bind) 1000 if (!f->netnsok && net != &init_net)
1001 err = f->mcast_bind(fam_grp); 1001 err = -ENOENT;
1002 else if (f->mcast_bind)
1003 err = f->mcast_bind(net, fam_grp);
1002 else 1004 else
1003 err = 0; 1005 err = 0;
1004 found = true; 1006 found = true;
@@ -1014,7 +1016,7 @@ static int genl_bind(int group)
1014 return err; 1016 return err;
1015} 1017}
1016 1018
1017static void genl_unbind(int group) 1019static void genl_unbind(struct net *net, int group)
1018{ 1020{
1019 int i; 1021 int i;
1020 bool found = false; 1022 bool found = false;
@@ -1029,7 +1031,7 @@ static void genl_unbind(int group)
1029 int fam_grp = group - f->mcgrp_offset; 1031 int fam_grp = group - f->mcgrp_offset;
1030 1032
1031 if (f->mcast_unbind) 1033 if (f->mcast_unbind)
1032 f->mcast_unbind(fam_grp); 1034 f->mcast_unbind(net, fam_grp);
1033 found = true; 1035 found = true;
1034 break; 1036 break;
1035 } 1037 }