From c380d9a7afff0e4c2e5f3c1c2dc7d2f4214dd962 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Dec 2014 20:54:40 +0100 Subject: genetlink: pass multicast bind/unbind to families In order to make the newly fixed multicast bind/unbind functionality in generic netlink, pass them down to the appropriate family. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- net/netlink/genetlink.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'net/netlink/genetlink.c') diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 76393f2f4b22..05bf40bbd189 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -983,11 +983,70 @@ static struct genl_multicast_group genl_ctrl_groups[] = { { .name = "notify", }, }; +static int genl_bind(int group) +{ + int i, err; + bool found = false; + + down_read(&cb_lock); + for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { + struct genl_family *f; + + list_for_each_entry(f, genl_family_chain(i), family_list) { + if (group >= f->mcgrp_offset && + group < f->mcgrp_offset + f->n_mcgrps) { + int fam_grp = group - f->mcgrp_offset; + + if (f->mcast_bind) + err = f->mcast_bind(fam_grp); + else + err = 0; + found = true; + break; + } + } + } + up_read(&cb_lock); + + if (WARN_ON(!found)) + err = 0; + + return err; +} + +static void genl_unbind(int group) +{ + int i; + bool found = false; + + down_read(&cb_lock); + for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { + struct genl_family *f; + + list_for_each_entry(f, genl_family_chain(i), family_list) { + if (group >= f->mcgrp_offset && + group < f->mcgrp_offset + f->n_mcgrps) { + int fam_grp = group - f->mcgrp_offset; + + if (f->mcast_unbind) + f->mcast_unbind(fam_grp); + found = true; + break; + } + } + } + up_read(&cb_lock); + + WARN_ON(!found); +} + static int __net_init genl_pernet_init(struct net *net) { struct netlink_kernel_cfg cfg = { .input = genl_rcv, .flags = NL_CFG_F_NONROOT_RECV, + .bind = genl_bind, + .unbind = genl_unbind, }; /* we'll bump the group number right afterwards */ -- cgit v1.2.3 From 023e2cfa36c31b0ad28c159a1bb0d61ff57334c8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Dec 2014 21:00:06 +0100 Subject: 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 Signed-off-by: David S. Miller --- net/netlink/genetlink.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'net/netlink/genetlink.c') 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[] = { { .name = "notify", }, }; -static int genl_bind(int group) +static int genl_bind(struct net *net, int group) { int i, err; bool found = false; @@ -997,8 +997,10 @@ static int genl_bind(int group) group < f->mcgrp_offset + f->n_mcgrps) { int fam_grp = group - f->mcgrp_offset; - if (f->mcast_bind) - err = f->mcast_bind(fam_grp); + if (!f->netnsok && net != &init_net) + err = -ENOENT; + else if (f->mcast_bind) + err = f->mcast_bind(net, fam_grp); else err = 0; found = true; @@ -1014,7 +1016,7 @@ static int genl_bind(int group) return err; } -static void genl_unbind(int group) +static void genl_unbind(struct net *net, int group) { int i; bool found = false; @@ -1029,7 +1031,7 @@ static void genl_unbind(int group) int fam_grp = group - f->mcgrp_offset; if (f->mcast_unbind) - f->mcast_unbind(fam_grp); + f->mcast_unbind(net, fam_grp); found = true; break; } -- cgit v1.2.3 From dc97a1a9477f969e34b38ca9d9cd231cb93ebea2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 29 Dec 2014 16:31:49 -0500 Subject: genetlink: A genl_bind() to an out-of-range multicast group should not WARN(). Users can request to bind to arbitrary multicast groups, so warning when the requested group number is out of range is not appropriate. And with the warning removed, and the 'err' variable properly given an initial value, we can remove 'found' altogether. Reported-by: Sedat Dilek Signed-off-by: David S. Miller --- net/netlink/genetlink.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'net/netlink/genetlink.c') diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 91566ed36c43..2e11061ef885 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -985,8 +985,7 @@ static struct genl_multicast_group genl_ctrl_groups[] = { static int genl_bind(struct net *net, int group) { - int i, err; - bool found = false; + int i, err = 0; down_read(&cb_lock); for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { @@ -1003,16 +1002,12 @@ static int genl_bind(struct net *net, int group) err = f->mcast_bind(net, fam_grp); else err = 0; - found = true; break; } } } up_read(&cb_lock); - if (WARN_ON(!found)) - err = 0; - return err; } -- cgit v1.2.3