[NET]: Make device event notification network namespace safe

Every user of the network device notifiers is either a protocol
stack or a pseudo device.  If a protocol stack that does not have
support for multiple network namespaces receives an event for a
device that is not in the initial network namespace it quite possibly
can get confused and do the wrong thing.

To avoid problems until all of the protocol stacks are converted
this patch modifies all netdev event handlers to ignore events on
devices that are not in the initial network namespace.

As the rest of the code is made network namespace aware these
checks can be removed.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric W. Biederman 2007-09-12 13:02:17 +02:00 committed by David S. Miller
parent e730c15519
commit e9dc865340
38 changed files with 126 additions and 1 deletions

View File

@ -294,6 +294,9 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr)
return NOTIFY_DONE;
}
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE;
/*

View File

@ -3299,6 +3299,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
{
struct net_device *event_dev = (struct net_device *)ptr;
if (event_dev->nd_net != &init_net)
return NOTIFY_DONE;
dprintk("event_dev: %s, event: %lx\n",
(event_dev ? event_dev->name : "None"),
event);

View File

@ -563,6 +563,9 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
{
struct net_device *dev = (struct net_device *)ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (!dev_is_ethdev(dev))
return NOTIFY_DONE;

View File

@ -301,6 +301,9 @@ static int pppoe_device_event(struct notifier_block *this,
{
struct net_device *dev = (struct net_device *) ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
/* Only look at sockets that are using this specific device. */
switch (event) {
case NETDEV_CHANGEMTU:

View File

@ -513,6 +513,9 @@ static int dlci_dev_event(struct notifier_block *unused,
{
struct net_device *dev = (struct net_device *) ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event == NETDEV_UNREGISTER) {
struct dlci_local *dlp;

View File

@ -109,6 +109,9 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event,
unsigned long flags;
int on;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (dev->get_stats != hdlc_get_stats)
return NOTIFY_DONE; /* not an HDLC device */

View File

@ -394,6 +394,9 @@ static int lapbeth_device_event(struct notifier_block *this,
struct lapbethdev *lapbeth;
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (!dev_is_ethdev(dev))
return NOTIFY_DONE;

View File

@ -31,6 +31,7 @@
#include <net/arp.h>
#include <linux/rtnetlink.h>
#include <linux/notifier.h>
#include <net/net_namespace.h>
#include <linux/if_vlan.h>
#include "vlan.h"
@ -603,6 +604,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
int i, flgs;
struct net_device *vlandev;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (!grp)
goto out;

View File

@ -333,6 +333,9 @@ static int aarp_device_event(struct notifier_block *this, unsigned long event,
struct net_device *dev = ptr;
int ct;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event == NETDEV_DOWN) {
write_lock_bh(&aarp_lock);

View File

@ -649,6 +649,9 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event,
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event == NETDEV_DOWN)
/* Discard any use of this */
atalk_dev_down(dev);

View File

@ -612,6 +612,9 @@ static int clip_device_event(struct notifier_block *this, unsigned long event,
{
struct net_device *dev = arg;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event == NETDEV_UNREGISTER) {
neigh_ifdown(&clip_tbl, dev);
return NOTIFY_DONE;

View File

@ -956,6 +956,10 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo
struct lec_priv *priv;
dev = (struct net_device *)dev_ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (dev->name == NULL || strncmp(dev->name, "lec", 3))
return NOTIFY_DONE; /* we are only interested in lec:s */

View File

@ -104,6 +104,9 @@ static int ax25_device_event(struct notifier_block *this, unsigned long event,
{
struct net_device *dev = (struct net_device *)ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
/* Reject non AX.25 devices */
if (dev->type != ARPHRD_AX25)
return NOTIFY_DONE;

View File

@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/rtnetlink.h>
#include <net/net_namespace.h>
#include "br_private.h"
@ -36,6 +37,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
struct net_bridge_port *p = dev->br_port;
struct net_bridge *br;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
/* not a port of a bridge */
if (p == NULL)
return NOTIFY_DONE;

View File

@ -15,6 +15,7 @@
#include <linux/skbuff.h>
#include <linux/string.h>
#include <linux/types.h>
#include <net/net_namespace.h>
#include <net/dst.h>
@ -252,6 +253,9 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, void
struct net_device *dev = ptr;
struct dst_entry *dst;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
switch (event) {
case NETDEV_UNREGISTER:
case NETDEV_DOWN:

View File

@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <net/net_namespace.h>
#include <net/fib_rules.h>
static LIST_HEAD(rules_ops);
@ -596,6 +597,9 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
struct net_device *dev = ptr;
struct fib_rules_ops *ops;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
ASSERT_RTNL();
rcu_read_lock();

View File

@ -1975,6 +1975,9 @@ static int pktgen_device_event(struct notifier_block *unused,
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
/* It is OK that we do not hold the group lock right now,
* as we run under the RTNL lock.
*/

View File

@ -1286,6 +1286,10 @@ static void rtnetlink_rcv(struct sock *sk, int len)
static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
switch (event) {
case NETDEV_UNREGISTER:
rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);

View File

@ -2089,6 +2089,9 @@ static int dn_device_event(struct notifier_block *this, unsigned long event,
{
struct net_device *dev = (struct net_device *)ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
switch(event) {
case NETDEV_UP:
dn_dev_up(dev);

View File

@ -1122,6 +1122,9 @@ static int econet_notifier(struct notifier_block *this, unsigned long msg, void
struct net_device *dev = (struct net_device *)data;
struct ec_device *edev;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
switch (msg) {
case NETDEV_UNREGISTER:
/* A device has gone down - kill any data we hold for it. */

View File

@ -1205,6 +1205,9 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
switch (event) {
case NETDEV_CHANGEADDR:
neigh_changeaddr(&arp_tbl, dev);

View File

@ -1051,6 +1051,9 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
struct net_device *dev = ptr;
struct in_device *in_dev = __in_dev_get_rtnl(dev);
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
ASSERT_RTNL();
if (!in_dev) {

View File

@ -860,6 +860,9 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
struct net_device *dev = ptr;
struct in_device *in_dev = __in_dev_get_rtnl(dev);
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event == NETDEV_UNREGISTER) {
fib_disable_ip(dev, 2);
return NOTIFY_DONE;

View File

@ -1083,13 +1083,18 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
struct vif_device *v;
int ct;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event != NETDEV_UNREGISTER)
return NOTIFY_DONE;
v=&vif_table[0];
for (ct=0;ct<maxvif;ct++,v++) {
if (v->dev==ptr)
if (v->dev==dev)
vif_delete(ct);
}
return NOTIFY_DONE;

View File

@ -557,6 +557,9 @@ ipq_rcv_dev_event(struct notifier_block *this,
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
/* Drop any packets associated with the downed device */
if (event == NETDEV_DOWN)
ipq_dev_drop(dev->ifindex);

View File

@ -125,6 +125,9 @@ static int masq_device_event(struct notifier_block *this,
{
const struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event == NETDEV_DOWN) {
/* Device was downed. Search entire table for
conntracks which were associated with that device,

View File

@ -2259,6 +2259,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
int run_pending = 0;
int err;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
switch(event) {
case NETDEV_REGISTER:
if (!idev && dev->mtu >= IPV6_MIN_MTU) {

View File

@ -1525,6 +1525,9 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
switch (event) {
case NETDEV_CHANGEADDR:
neigh_changeaddr(&nd_tbl, dev);

View File

@ -547,6 +547,9 @@ ipq_rcv_dev_event(struct notifier_block *this,
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
/* Drop any packets associated with the downed device */
if (event == NETDEV_DOWN)
ipq_dev_drop(dev->ifindex);

View File

@ -347,6 +347,9 @@ static int ipxitf_device_event(struct notifier_block *notifier,
struct net_device *dev = ptr;
struct ipx_interface *i, *tmp;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event != NETDEV_DOWN && event != NETDEV_UP)
goto out;

View File

@ -734,6 +734,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this,
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
/* Drop any packets associated with the downed device */
if (event == NETDEV_DOWN)
nfqnl_dev_drop(dev->ifindex);

View File

@ -106,6 +106,9 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi
{
struct net_device *dev = (struct net_device *)ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event != NETDEV_DOWN)
return NOTIFY_DONE;

View File

@ -1477,6 +1477,9 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void
struct hlist_node *node;
struct net_device *dev = data;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
read_lock(&packet_sklist_lock);
sk_for_each(sk, node, &packet_sklist) {
struct packet_sock *po = pkt_sk(sk);

View File

@ -197,6 +197,9 @@ static int rose_device_event(struct notifier_block *this, unsigned long event,
{
struct net_device *dev = (struct net_device *)ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event != NETDEV_DOWN)
return NOTIFY_DONE;

View File

@ -198,6 +198,9 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
struct eth_bearer *eb_ptr = &eth_bearers[0];
struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
while ((eb_ptr->dev != dev)) {
if (++eb_ptr == stop)
return NOTIFY_DONE; /* couldn't find device */

View File

@ -191,6 +191,9 @@ static int x25_device_event(struct notifier_block *this, unsigned long event,
struct net_device *dev = ptr;
struct x25_neigh *nb;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (dev->type == ARPHRD_X25
#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
|| dev->type == ARPHRD_ETHER

View File

@ -2236,6 +2236,11 @@ static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo)
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
switch (event) {
case NETDEV_DOWN:
xfrm_flush_bundles();

View File

@ -20,6 +20,7 @@
#include <linux/notifier.h>
#include <linux/netdevice.h>
#include <linux/rcupdate.h>
#include <net/net_namespace.h>
#include "security.h"
#include "objsec.h"
@ -234,6 +235,9 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
{
struct net_device *dev = ptr;
if (dev->nd_net != &init_net)
return NOTIFY_DONE;
if (event == NETDEV_DOWN)
sel_netif_kill(dev);