From 3ad7d2468f79fc13215eb941f766a692d34b1381 Mon Sep 17 00:00:00 2001 From: Krister Johansen Date: Thu, 8 Jun 2017 13:12:14 -0700 Subject: Ipvlan should return an error when an address is already in use. The ipvlan code already knows how to detect when a duplicate address is about to be assigned to an ipvlan device. However, that failure is not propogated outward and leads to a silent failure. Introduce a validation step at ip address creation time and allow device drivers to register to validate the incoming ip addresses. The ipvlan code is the first consumer. If it detects an address in use, we can return an error to the user before beginning to commit the new ifa in the networking code. This can be especially useful if it is necessary to provision many ipvlans in containers. The provisioning software (or operator) can use this to detect situations where an ip address is unexpectedly in use. Signed-off-by: Krister Johansen Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/linux/inetdevice.h') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index a2e9d6ea1349..e7c04c4e4bcd 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -150,8 +150,15 @@ struct in_ifaddr { unsigned long ifa_tstamp; /* updated timestamp */ }; +struct in_validator_info { + __be32 ivi_addr; + struct in_device *ivi_dev; +}; + int register_inetaddr_notifier(struct notifier_block *nb); int unregister_inetaddr_notifier(struct notifier_block *nb); +int register_inetaddr_validator_notifier(struct notifier_block *nb); +int unregister_inetaddr_validator_notifier(struct notifier_block *nb); void inet_netconf_notify_devconf(struct net *net, int event, int type, int ifindex, struct ipv4_devconf *devconf); -- cgit v1.2.3 From 7658b36f1b3122c298213eed344f622e836b281b Mon Sep 17 00:00:00 2001 From: "Reshetova, Elena" Date: Fri, 30 Jun 2017 13:08:03 +0300 Subject: net: convert in_device.refcnt from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 11 ++++++----- net/ipv4/devinet.c | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'include/linux/inetdevice.h') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index e7c04c4e4bcd..fb3f809e34e4 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -11,6 +11,7 @@ #include #include #include +#include struct ipv4_devconf { void *sysctl; @@ -22,7 +23,7 @@ struct ipv4_devconf { struct in_device { struct net_device *dev; - atomic_t refcnt; + refcount_t refcnt; int dead; struct in_ifaddr *ifa_list; /* IP ifaddr chain */ @@ -219,7 +220,7 @@ static inline struct in_device *in_dev_get(const struct net_device *dev) rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); if (in_dev) - atomic_inc(&in_dev->refcnt); + refcount_inc(&in_dev->refcnt); rcu_read_unlock(); return in_dev; } @@ -240,12 +241,12 @@ void in_dev_finish_destroy(struct in_device *idev); static inline void in_dev_put(struct in_device *idev) { - if (atomic_dec_and_test(&idev->refcnt)) + if (refcount_dec_and_test(&idev->refcnt)) in_dev_finish_destroy(idev); } -#define __in_dev_put(idev) atomic_dec(&(idev)->refcnt) -#define in_dev_hold(idev) atomic_inc(&(idev)->refcnt) +#define __in_dev_put(idev) refcount_dec(&(idev)->refcnt) +#define in_dev_hold(idev) refcount_inc(&(idev)->refcnt) #endif /* __KERNEL__ */ diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index a7dd088d5fc9..38d9af9b917c 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -252,7 +252,7 @@ static struct in_device *inetdev_init(struct net_device *dev) /* Reference in_dev->dev */ dev_hold(dev); /* Account for reference dev->ip_ptr (below) */ - in_dev_hold(in_dev); + refcount_set(&in_dev->refcnt, 1); err = devinet_sysctl_register(in_dev); if (err) { -- cgit v1.2.3