nl80211: fix netns separation
There are currently a few ways to "escape" the network namespace and access a wiphy that belongs to another namespace. Add a netns argument to the relevant functions to fix this. One remaining issue with testmode will be fixed in a follow-up patch. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
7fee4778bf
commit
4f7eff10b2
|
@ -71,7 +71,7 @@ static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs,
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cfg80211_registered_device *
|
static struct cfg80211_registered_device *
|
||||||
__cfg80211_rdev_from_info(struct genl_info *info)
|
__cfg80211_rdev_from_info(struct net *netns, struct genl_info *info)
|
||||||
{
|
{
|
||||||
struct cfg80211_registered_device *rdev = NULL, *tmp;
|
struct cfg80211_registered_device *rdev = NULL, *tmp;
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
|
@ -88,7 +88,7 @@ __cfg80211_rdev_from_info(struct genl_info *info)
|
||||||
|
|
||||||
if (info->attrs[NL80211_ATTR_IFINDEX]) {
|
if (info->attrs[NL80211_ATTR_IFINDEX]) {
|
||||||
int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
|
int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
|
||||||
netdev = dev_get_by_index(genl_info_net(info), ifindex);
|
netdev = dev_get_by_index(netns, ifindex);
|
||||||
if (netdev) {
|
if (netdev) {
|
||||||
if (netdev->ieee80211_ptr)
|
if (netdev->ieee80211_ptr)
|
||||||
tmp = wiphy_to_dev(
|
tmp = wiphy_to_dev(
|
||||||
|
@ -110,10 +110,13 @@ __cfg80211_rdev_from_info(struct genl_info *info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rdev)
|
if (!rdev)
|
||||||
return rdev;
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
return ERR_PTR(-ENODEV);
|
if (netns != wiphy_net(&rdev->wiphy))
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
|
return rdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -137,12 +140,12 @@ __cfg80211_rdev_from_info(struct genl_info *info)
|
||||||
* be checked with IS_ERR() for errors.
|
* be checked with IS_ERR() for errors.
|
||||||
*/
|
*/
|
||||||
static struct cfg80211_registered_device *
|
static struct cfg80211_registered_device *
|
||||||
cfg80211_get_dev_from_info(struct genl_info *info)
|
cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
|
||||||
{
|
{
|
||||||
struct cfg80211_registered_device *rdev;
|
struct cfg80211_registered_device *rdev;
|
||||||
|
|
||||||
mutex_lock(&cfg80211_mutex);
|
mutex_lock(&cfg80211_mutex);
|
||||||
rdev = __cfg80211_rdev_from_info(info);
|
rdev = __cfg80211_rdev_from_info(netns, info);
|
||||||
|
|
||||||
/* if it is not an error we grab the lock on
|
/* if it is not an error we grab the lock on
|
||||||
* it to assure it won't be going away while
|
* it to assure it won't be going away while
|
||||||
|
@ -1419,7 +1422,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!netdev) {
|
if (!netdev) {
|
||||||
rdev = __cfg80211_rdev_from_info(info);
|
rdev = __cfg80211_rdev_from_info(genl_info_net(info), info);
|
||||||
if (IS_ERR(rdev)) {
|
if (IS_ERR(rdev)) {
|
||||||
mutex_unlock(&cfg80211_mutex);
|
mutex_unlock(&cfg80211_mutex);
|
||||||
return PTR_ERR(rdev);
|
return PTR_ERR(rdev);
|
||||||
|
@ -6623,7 +6626,7 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
|
||||||
if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
|
if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
|
||||||
rdev = cfg80211_get_dev_from_info(info);
|
rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
|
||||||
if (IS_ERR(rdev)) {
|
if (IS_ERR(rdev)) {
|
||||||
if (rtnl)
|
if (rtnl)
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
Reference in New Issue