mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 00:20:32 +00:00
wireguard: device: clear keys on VM fork
When a virtual machine forks, it's important that WireGuard clear existing sessions so that different plaintexts are not transmitted using the same key+nonce, which can result in catastrophic cryptographic failure. To accomplish this, we simply hook into the newly added vmfork notifier. As a bonus, it turns out that, like the vmfork registration function, the PM registration function is stubbed out when CONFIG_PM_SLEEP is not set, so we can actually just remove the maze of ifdefs, which makes it really quite clean to support both notifiers at once. Cc: Dominik Brodowski <linux@dominikbrodowski.net> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Theodore Ts'o <tytso@mit.edu> Acked-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
f3c2682bad
commit
2d6919c320
1 changed files with 27 additions and 11 deletions
|
@ -59,9 +59,7 @@ static int wg_open(struct net_device *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
static int wg_pm_notification(struct notifier_block *nb, unsigned long action, void *data)
|
||||||
static int wg_pm_notification(struct notifier_block *nb, unsigned long action,
|
|
||||||
void *data)
|
|
||||||
{
|
{
|
||||||
struct wg_device *wg;
|
struct wg_device *wg;
|
||||||
struct wg_peer *peer;
|
struct wg_peer *peer;
|
||||||
|
@ -92,7 +90,24 @@ static int wg_pm_notification(struct notifier_block *nb, unsigned long action,
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct notifier_block pm_notifier = { .notifier_call = wg_pm_notification };
|
static struct notifier_block pm_notifier = { .notifier_call = wg_pm_notification };
|
||||||
#endif
|
|
||||||
|
static int wg_vm_notification(struct notifier_block *nb, unsigned long action, void *data)
|
||||||
|
{
|
||||||
|
struct wg_device *wg;
|
||||||
|
struct wg_peer *peer;
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
list_for_each_entry(wg, &device_list, device_list) {
|
||||||
|
mutex_lock(&wg->device_update_lock);
|
||||||
|
list_for_each_entry(peer, &wg->peer_list, peer_list)
|
||||||
|
wg_noise_expire_current_peer_keypairs(peer);
|
||||||
|
mutex_unlock(&wg->device_update_lock);
|
||||||
|
}
|
||||||
|
rtnl_unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block vm_notifier = { .notifier_call = wg_vm_notification };
|
||||||
|
|
||||||
static int wg_stop(struct net_device *dev)
|
static int wg_stop(struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
@ -424,15 +439,17 @@ int __init wg_device_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
ret = register_pm_notifier(&pm_notifier);
|
ret = register_pm_notifier(&pm_notifier);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
#endif
|
|
||||||
|
ret = register_random_vmfork_notifier(&vm_notifier);
|
||||||
|
if (ret)
|
||||||
|
goto error_pm;
|
||||||
|
|
||||||
ret = register_pernet_device(&pernet_ops);
|
ret = register_pernet_device(&pernet_ops);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error_pm;
|
goto error_vm;
|
||||||
|
|
||||||
ret = rtnl_link_register(&link_ops);
|
ret = rtnl_link_register(&link_ops);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -442,10 +459,10 @@ int __init wg_device_init(void)
|
||||||
|
|
||||||
error_pernet:
|
error_pernet:
|
||||||
unregister_pernet_device(&pernet_ops);
|
unregister_pernet_device(&pernet_ops);
|
||||||
|
error_vm:
|
||||||
|
unregister_random_vmfork_notifier(&vm_notifier);
|
||||||
error_pm:
|
error_pm:
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
unregister_pm_notifier(&pm_notifier);
|
unregister_pm_notifier(&pm_notifier);
|
||||||
#endif
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,8 +470,7 @@ void wg_device_uninit(void)
|
||||||
{
|
{
|
||||||
rtnl_link_unregister(&link_ops);
|
rtnl_link_unregister(&link_ops);
|
||||||
unregister_pernet_device(&pernet_ops);
|
unregister_pernet_device(&pernet_ops);
|
||||||
#ifdef CONFIG_PM_SLEEP
|
unregister_random_vmfork_notifier(&vm_notifier);
|
||||||
unregister_pm_notifier(&pm_notifier);
|
unregister_pm_notifier(&pm_notifier);
|
||||||
#endif
|
|
||||||
rcu_barrier();
|
rcu_barrier();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue