lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 13 Mar 2017 00:01:42 +0100
From:   Hannes Frederic Sowa <hannes@...essinduktion.org>
To:     netdev@...r.kernel.org
Subject: [PATCH net-next RFC v1 18/27] afnetns: afnetns should influence source address selection

Signed-off-by: Hannes Frederic Sowa <hannes@...essinduktion.org>
---
 drivers/target/iscsi/cxgbit/cxgbit_cm.c |  2 +-
 include/linux/inetdevice.h              |  5 +++--
 include/net/route.h                     | 10 ++++++----
 net/ipv4/devinet.c                      | 19 ++++++++++++++++---
 net/ipv4/icmp.c                         |  4 ++--
 net/ipv4/igmp.c                         |  2 +-
 net/ipv4/route.c                        | 21 ++++++++++++---------
 net/ipv4/xfrm4_policy.c                 |  2 +-
 net/sctp/protocol.c                     |  4 ++--
 net/tipc/udp_media.c                    |  2 +-
 10 files changed, 45 insertions(+), 26 deletions(-)

diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c
index 37a05185dcbe0e..4ae59d20d8e260 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c
@@ -266,7 +266,7 @@ static struct net_device *cxgbit_ipv4_netdev(__be32 saddr)
 {
 	struct net_device *ndev;
 
-	ndev = __ip_dev_find(&init_net, saddr, false);
+	ndev = __ip_dev_find(&init_net, NULL, saddr, false);
 	if (!ndev)
 		return NULL;
 
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index a41bfce099e0a1..9411270cb0fe64 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -160,10 +160,11 @@ void inet_netconf_notify_devconf(struct net *net, int type, int ifindex,
 				 struct ipv4_devconf *devconf);
 
 struct in_ifaddr *ifa_find_rcu(struct net *net, __be32 addr);
-struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref);
+struct net_device *__ip_dev_find(struct net *net, struct afnetns *afnetns,
+				 __be32 addr, bool devref);
 static inline struct net_device *ip_dev_find(struct net *net, __be32 addr)
 {
-	return __ip_dev_find(net, addr, true);
+	return __ip_dev_find(net, NULL, addr, true);
 }
 
 int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b);
diff --git a/include/net/route.h b/include/net/route.h
index c0874c87c17371..d29449d1863636 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -113,13 +113,15 @@ struct in_device;
 int ip_rt_init(void);
 void rt_cache_flush(struct net *net);
 void rt_flush_dev(struct net_device *dev);
-struct rtable *__ip_route_output_key_hash(struct net *, struct flowi4 *flp,
-					  int mp_hash);
+struct rtable *__ip_route_output_key_hash(struct net *net,
+					  struct afnetns *afnetns,
+					  struct flowi4 *flp, int mp_hash);
 
 static inline struct rtable *__ip_route_output_key(struct net *net,
+						   struct afnetns *afnetns,
 						   struct flowi4 *flp)
 {
-	return __ip_route_output_key_hash(net, flp, -1);
+	return __ip_route_output_key_hash(net, afnetns, flp, -1);
 }
 
 struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp,
@@ -286,7 +288,7 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
 			      sport, dport, sk);
 
 	if (!dst || !src) {
-		rt = __ip_route_output_key(net, fl4);
+		rt = __ip_route_output_key(net, NULL, fl4);
 		if (IS_ERR(rt))
 			return rt;
 		ip_rt_put(rt);
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 0844d917aa8d7d..82a7389ec86faa 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -150,14 +150,27 @@ struct in_ifaddr *ifa_find_rcu(struct net *net, __be32 addr)
  *
  * If a caller uses devref=false, it should be protected by RCU, or RTNL
  */
-struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
+struct net_device *__ip_dev_find(struct net *net, struct afnetns *afnetns,
+				 __be32 addr, bool devref)
 {
-	struct net_device *result;
+	struct net_device *result = NULL;
 	struct in_ifaddr *ifa;
 
 	rcu_read_lock();
 	ifa = ifa_find_rcu(net, addr);
-	result = ifa ? ifa->ifa_dev->dev : NULL;
+#if IS_ENABLED(CONFIG_AFNETNS)
+	if (afnetns && afnetns != net->afnet_ns) {
+		/* we are in a child namespace, thus only allow to
+		 * explicitly configured addresses
+		 */
+		if (!ifa || ifa->afnetns != afnetns) {
+			rcu_read_unlock();
+			return NULL;
+		}
+	}
+#endif
+	if (ifa)
+		result = ifa->ifa_dev->dev;
 	if (!result) {
 		struct flowi4 fl4 = { .daddr = addr };
 		struct fib_result res = { 0 };
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index fc310db2708bf6..74261d6b86e4fc 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -505,7 +505,7 @@ static struct rtable *icmp_route_lookup(struct net *net,
 	fl4->flowi4_oif = l3mdev_master_ifindex(skb_dst(skb_in)->dev);
 
 	security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4));
-	rt = __ip_route_output_key_hash(net, fl4,
+	rt = __ip_route_output_key_hash(net, NULL, fl4,
 					icmp_multipath_hash_skb(skb_in));
 	if (IS_ERR(rt))
 		return rt;
@@ -529,7 +529,7 @@ static struct rtable *icmp_route_lookup(struct net *net,
 
 	if (inet_addr_type_dev_table(net, skb_dst(skb_in)->dev,
 				     fl4_dec.saddr) == RTN_LOCAL) {
-		rt2 = __ip_route_output_key(net, &fl4_dec);
+		rt2 = __ip_route_output_key(net, NULL, &fl4_dec);
 		if (IS_ERR(rt2))
 			err = PTR_ERR(rt2);
 	} else {
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 44fd86de2823dd..d246bf1704f4d8 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1754,7 +1754,7 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
 		return idev;
 	}
 	if (imr->imr_address.s_addr) {
-		dev = __ip_dev_find(net, imr->imr_address.s_addr, false);
+		dev = __ip_dev_find(net, NULL, imr->imr_address.s_addr, false);
 		if (!dev)
 			return NULL;
 	}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 8471dd11677146..f3304647082182 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1045,7 +1045,7 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
 
 	__build_flow_key(net, &fl4, NULL, iph, oif,
 			 RT_TOS(iph->tos), protocol, mark, flow_flags);
-	rt = __ip_route_output_key(net, &fl4);
+	rt = __ip_route_output_key(net, NULL, &fl4);
 	if (!IS_ERR(rt)) {
 		__ip_rt_update_pmtu(rt, &fl4, mtu);
 		ip_rt_put(rt);
@@ -1064,7 +1064,7 @@ static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
 	if (!fl4.flowi4_mark)
 		fl4.flowi4_mark = IP4_REPLY_MARK(sock_net(sk), skb->mark);
 
-	rt = __ip_route_output_key(sock_net(sk), &fl4);
+	rt = __ip_route_output_key(sock_net(sk), NULL, &fl4);
 	if (!IS_ERR(rt)) {
 		__ip_rt_update_pmtu(rt, &fl4, mtu);
 		ip_rt_put(rt);
@@ -1134,7 +1134,7 @@ void ipv4_redirect(struct sk_buff *skb, struct net *net,
 
 	__build_flow_key(net, &fl4, NULL, iph, oif,
 			 RT_TOS(iph->tos), protocol, mark, flow_flags);
-	rt = __ip_route_output_key(net, &fl4);
+	rt = __ip_route_output_key(net, NULL, &fl4);
 	if (!IS_ERR(rt)) {
 		__ip_do_redirect(rt, skb, &fl4, false);
 		ip_rt_put(rt);
@@ -1150,7 +1150,7 @@ void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk)
 	struct net *net = sock_net(sk);
 
 	__build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0);
-	rt = __ip_route_output_key(net, &fl4);
+	rt = __ip_route_output_key(net, NULL, &fl4);
 	if (!IS_ERR(rt)) {
 		__ip_do_redirect(rt, skb, &fl4, false);
 		ip_rt_put(rt);
@@ -2202,8 +2202,9 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
  * Major route resolver routine.
  */
 
-struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4,
-					  int mp_hash)
+struct rtable *__ip_route_output_key_hash(struct net *net,
+					  struct afnetns *afnetns,
+					  struct flowi4 *fl4, int mp_hash)
 {
 	struct net_device *dev_out = NULL;
 	__u8 tos = RT_FL_TOS(fl4);
@@ -2244,7 +2245,7 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4,
 		    (ipv4_is_multicast(fl4->daddr) ||
 		     ipv4_is_lbcast(fl4->daddr))) {
 			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
-			dev_out = __ip_dev_find(net, fl4->saddr, false);
+			dev_out = __ip_dev_find(net, NULL, fl4->saddr, false);
 			if (!dev_out)
 				goto out;
 
@@ -2269,7 +2270,7 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4,
 
 		if (!(fl4->flowi4_flags & FLOWI_FLAG_ANYSRC)) {
 			/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
-			if (!__ip_dev_find(net, fl4->saddr, false))
+			if (!__ip_dev_find(net, afnetns, fl4->saddr, false))
 				goto out;
 		}
 	}
@@ -2458,7 +2459,9 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
 struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4,
 				    const struct sock *sk)
 {
-	struct rtable *rt = __ip_route_output_key(net, flp4);
+	struct rtable *rt;
+
+	rt = __ip_route_output_key(net, sk ? sock_afnetns(sk) : NULL, flp4);
 
 	if (IS_ERR(rt))
 		return rt;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 71b4ecc195c707..c8d9eaa59be8fc 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -33,7 +33,7 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
 
 	fl4->flowi4_flags = FLOWI_FLAG_SKIP_NH_OIF;
 
-	rt = __ip_route_output_key(net, fl4);
+	rt = __ip_route_output_key(net, NULL, fl4);
 	if (!IS_ERR(rt))
 		return &rt->dst;
 
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 1b6d4574d2b02a..cd77ec87c5f9ef 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -520,8 +520,8 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
 		/* Ensure the src address belongs to the output
 		 * interface.
 		 */
-		odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr,
-				     false);
+		odev = __ip_dev_find(sock_net(sk), NULL,
+				     laddr->a.v4.sin_addr.s_addr, false);
 		if (!odev || odev->ifindex != fl4->flowi4_oif) {
 			if (&rt->dst != dst)
 				dst_release(&rt->dst);
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index 46061cf48cd135..98bc29e63058a2 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -688,7 +688,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
 	if (local.proto == htons(ETH_P_IP)) {
 		struct net_device *dev;
 
-		dev = __ip_dev_find(net, local.ipv4.s_addr, false);
+		dev = __ip_dev_find(net, NULL, local.ipv4.s_addr, false);
 		if (!dev) {
 			err = -ENODEV;
 			goto err;
-- 
2.9.3

Powered by blists - more mailing lists