Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211_hwsim: Allow managing radios from non-initial namespaces

While wiphys can be moved into network namespaces over nl80211, the
creation and removal of hwsim radios is currently limited to the initial
namespace. This patch allows management of namespaced radios from the
owning namespace by setting genetlink netnsok.

To prevent two arbitrary namespaces to communicate over the simulated
shared medium, radios are separated by netgroups. Each radio created in
the same namespace lives in the same netgroup and hence can communicate
with other radios in that group. When moving radios to other namespaces,
the netgroup is preserved, so two radios having the same netgroup can
communicate even if not in the same namespace; This allows a controlling
namespace to create radios and move them to other namespaces for
communication.

When a net namespace owning a radio exits, the radio is destroyed unless
it was created in the initial network namespace. This keeps the previous
behavior by returning them to the init namespace, but prevents unprivileged
users from creating radios in the initial namespace.

Signed-off-by: Martin Willi <martin@strongswan.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Martin Willi and committed by
Johannes Berg
100cb9ff 5617c6cd

+94 -3
+94 -3
drivers/net/wireless/mac80211_hwsim.c
··· 30 30 #include <linux/module.h> 31 31 #include <linux/ktime.h> 32 32 #include <net/genetlink.h> 33 + #include <net/net_namespace.h> 34 + #include <net/netns/generic.h> 33 35 #include "mac80211_hwsim.h" 34 36 35 37 #define WARN_QUEUE 100 ··· 250 248 { 251 249 struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; 252 250 cp->magic = 0; 251 + } 252 + 253 + static unsigned int hwsim_net_id; 254 + 255 + static int hwsim_netgroup; 256 + 257 + struct hwsim_net { 258 + int netgroup; 259 + }; 260 + 261 + static inline int hwsim_net_get_netgroup(struct net *net) 262 + { 263 + struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 264 + 265 + return hwsim_net->netgroup; 266 + } 267 + 268 + static inline void hwsim_net_set_netgroup(struct net *net) 269 + { 270 + struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id); 271 + 272 + hwsim_net->netgroup = hwsim_netgroup++; 253 273 } 254 274 255 275 static struct class *hwsim_class; ··· 550 526 */ 551 527 u64 group; 552 528 529 + /* group shared by radios created in the same netns */ 530 + int netgroup; 531 + 553 532 int power_level; 554 533 555 534 /* difference between this hw's clock and the real clock, in usecs */ ··· 595 568 .name = "MAC80211_HWSIM", 596 569 .version = 1, 597 570 .maxattr = HWSIM_ATTR_MAX, 571 + .netnsok = true, 598 572 }; 599 573 600 574 enum hwsim_multicast_groups { ··· 1228 1200 continue; 1229 1201 1230 1202 if (!(data->group & data2->group)) 1203 + continue; 1204 + 1205 + if (data->netgroup != data2->netgroup) 1231 1206 continue; 1232 1207 1233 1208 if (!hwsim_chans_compat(chan, data2->tmp_chan) && ··· 2380 2349 struct ieee80211_hw *hw; 2381 2350 enum nl80211_band band; 2382 2351 const struct ieee80211_ops *ops = &mac80211_hwsim_ops; 2352 + struct net *net; 2383 2353 int idx; 2384 2354 2385 2355 if (WARN_ON(param->channels > 1 && !param->use_chanctx)) ··· 2398 2366 err = -ENOMEM; 2399 2367 goto failed; 2400 2368 } 2369 + 2370 + if (info) 2371 + net = genl_info_net(info); 2372 + else 2373 + net = &init_net; 2374 + wiphy_net_set(hw->wiphy, net); 2375 + 2401 2376 data = hw->priv; 2402 2377 data->hw = hw; 2403 2378 ··· 2579 2540 /* By default all radios belong to the first group */ 2580 2541 data->group = 1; 2581 2542 mutex_init(&data->mutex); 2543 + 2544 + data->netgroup = hwsim_net_get_netgroup(net); 2582 2545 2583 2546 /* Enable frame retransmissions for lossy channels */ 2584 2547 hw->max_rates = 4; ··· 3054 3013 continue; 3055 3014 } 3056 3015 3016 + if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 3017 + continue; 3018 + 3057 3019 list_del(&data->list); 3058 3020 spin_unlock_bh(&hwsim_radio_lock); 3059 3021 mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), ··· 3081 3037 spin_lock_bh(&hwsim_radio_lock); 3082 3038 list_for_each_entry(data, &hwsim_radios, list) { 3083 3039 if (data->idx != idx) 3040 + continue; 3041 + 3042 + if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) 3084 3043 continue; 3085 3044 3086 3045 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ··· 3125 3078 if (data->idx < idx) 3126 3079 continue; 3127 3080 3081 + if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk))) 3082 + continue; 3083 + 3128 3084 res = mac80211_hwsim_get_radio(skb, data, 3129 3085 NETLINK_CB(cb->skb).portid, 3130 3086 cb->nlh->nlmsg_seq, cb, ··· 3167 3117 .cmd = HWSIM_CMD_NEW_RADIO, 3168 3118 .policy = hwsim_genl_policy, 3169 3119 .doit = hwsim_new_radio_nl, 3170 - .flags = GENL_ADMIN_PERM, 3120 + .flags = GENL_UNS_ADMIN_PERM, 3171 3121 }, 3172 3122 { 3173 3123 .cmd = HWSIM_CMD_DEL_RADIO, 3174 3124 .policy = hwsim_genl_policy, 3175 3125 .doit = hwsim_del_radio_nl, 3176 - .flags = GENL_ADMIN_PERM, 3126 + .flags = GENL_UNS_ADMIN_PERM, 3177 3127 }, 3178 3128 { 3179 3129 .cmd = HWSIM_CMD_GET_RADIO, ··· 3255 3205 return -EINVAL; 3256 3206 } 3257 3207 3208 + static __net_init int hwsim_init_net(struct net *net) 3209 + { 3210 + hwsim_net_set_netgroup(net); 3211 + 3212 + return 0; 3213 + } 3214 + 3215 + static void __net_exit hwsim_exit_net(struct net *net) 3216 + { 3217 + struct mac80211_hwsim_data *data, *tmp; 3218 + 3219 + spin_lock_bh(&hwsim_radio_lock); 3220 + list_for_each_entry_safe(data, tmp, &hwsim_radios, list) { 3221 + if (!net_eq(wiphy_net(data->hw->wiphy), net)) 3222 + continue; 3223 + 3224 + /* Radios created in init_net are returned to init_net. */ 3225 + if (data->netgroup == hwsim_net_get_netgroup(&init_net)) 3226 + continue; 3227 + 3228 + list_del(&data->list); 3229 + INIT_WORK(&data->destroy_work, destroy_radio); 3230 + schedule_work(&data->destroy_work); 3231 + } 3232 + spin_unlock_bh(&hwsim_radio_lock); 3233 + } 3234 + 3235 + static struct pernet_operations hwsim_net_ops = { 3236 + .init = hwsim_init_net, 3237 + .exit = hwsim_exit_net, 3238 + .id = &hwsim_net_id, 3239 + .size = sizeof(struct hwsim_net), 3240 + }; 3241 + 3258 3242 static void hwsim_exit_netlink(void) 3259 3243 { 3260 3244 /* unregister the notifier */ ··· 3325 3241 spin_lock_init(&hwsim_radio_lock); 3326 3242 INIT_LIST_HEAD(&hwsim_radios); 3327 3243 3328 - err = platform_driver_register(&mac80211_hwsim_driver); 3244 + err = register_pernet_device(&hwsim_net_ops); 3329 3245 if (err) 3330 3246 return err; 3247 + 3248 + err = platform_driver_register(&mac80211_hwsim_driver); 3249 + if (err) 3250 + goto out_unregister_pernet; 3331 3251 3332 3252 hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim"); 3333 3253 if (IS_ERR(hwsim_class)) { ··· 3450 3362 mac80211_hwsim_free(); 3451 3363 out_unregister_driver: 3452 3364 platform_driver_unregister(&mac80211_hwsim_driver); 3365 + out_unregister_pernet: 3366 + unregister_pernet_device(&hwsim_net_ops); 3453 3367 return err; 3454 3368 } 3455 3369 module_init(init_mac80211_hwsim); ··· 3465 3375 mac80211_hwsim_free(); 3466 3376 unregister_netdev(hwsim_mon); 3467 3377 platform_driver_unregister(&mac80211_hwsim_driver); 3378 + unregister_pernet_device(&hwsim_net_ops); 3468 3379 } 3469 3380 module_exit(exit_mac80211_hwsim);