From: Daniel Lezcano <[EMAIL PROTECTED]>

Check the bind address is allowed. It must match ifaddr assigned to
the namespace and all derivative addresses.

Signed-off-by: Daniel Lezcano <[EMAIL PROTECTED]>

---
 include/linux/net_namespace.h |    7 +++++
 net/core/net_namespace.c      |   54 ++++++++++++++++++++++++++++++++++++++++++
 net/ipv4/af_inet.c            |    2 +
 net/ipv4/raw.c                |    3 ++
 4 files changed, 66 insertions(+)

Index: 2.6.20-rc4-mm1/net/ipv4/af_inet.c
===================================================================
--- 2.6.20-rc4-mm1.orig/net/ipv4/af_inet.c
+++ 2.6.20-rc4-mm1/net/ipv4/af_inet.c
@@ -433,6 +433,8 @@
         *  is temporarily down)
         */
        err = -EADDRNOTAVAIL;
+       if (net_ns_check_bind(chk_addr_ret, addr->sin_addr.s_addr))
+               goto out;
        if (!sysctl_ip_nonlocal_bind &&
            !inet->freebind &&
            addr->sin_addr.s_addr != INADDR_ANY &&
Index: 2.6.20-rc4-mm1/net/ipv4/raw.c
===================================================================
--- 2.6.20-rc4-mm1.orig/net/ipv4/raw.c
+++ 2.6.20-rc4-mm1/net/ipv4/raw.c
@@ -559,7 +559,10 @@
        if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))
                goto out;
        chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
+
        ret = -EADDRNOTAVAIL;
+       if (net_ns_check_bind(chk_addr_ret, addr->sin_addr.s_addr))
+               goto out;
        if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
            chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
                goto out;
Index: 2.6.20-rc4-mm1/include/linux/net_namespace.h
===================================================================
--- 2.6.20-rc4-mm1.orig/include/linux/net_namespace.h
+++ 2.6.20-rc4-mm1/include/linux/net_namespace.h
@@ -93,6 +93,8 @@
 
 extern int net_ns_ioctl(unsigned int cmd, void __user *arg);
 
+extern int net_ns_check_bind(int addr_type, u32 addr);
+
 #else /* CONFIG_NET_NS */
 
 #define INIT_NET_NS(net_ns)
@@ -148,6 +150,11 @@
        return -ENOSYS;
 }
 
+static inline int net_ns_check_bind(int addr_type, u32 addr)
+{
+       return 0;
+}
+
 #endif /* !CONFIG_NET_NS */
 
 #endif /* _LINUX_NET_NAMESPACE_H */
Index: 2.6.20-rc4-mm1/net/core/net_namespace.c
===================================================================
--- 2.6.20-rc4-mm1.orig/net/core/net_namespace.c
+++ 2.6.20-rc4-mm1/net/core/net_namespace.c
@@ -263,4 +263,58 @@
        return err;
 }
 
+/*
+ * This function check if the specified bind address is allowed.
+ * The bind is allowed if the address is:
+ * - 127.0.0.1
+ * - INADDR_ANY
+ * - INADDR_BROADCAST
+ * - a multicast address
+ * - the specified address match an ifaddr owned by the current
+ *   network namespace. That implies the local address and the
+ *   computed address from the netmask
+ * @addr_type : an addr type
+ * @addr : the requested bind address
+ * Returns: -EPERM on failure, 0 on success
+ */
+int net_ns_check_bind(int addr_type, u32 addr)
+{
+       int ret = -EPERM;
+        struct net_device *dev;
+        struct in_device *in_dev;
+       struct net_namespace *net_ns = current_net_ns;
+
+       if (LOOPBACK(addr) ||
+           MULTICAST(addr) ||
+           INADDR_ANY == addr ||
+           INADDR_BROADCAST == addr)
+               return 0;
+
+        read_lock(&dev_base_lock);
+        rcu_read_lock();
+        for (dev = dev_base; dev; dev = dev->next) {
+                in_dev = __in_dev_get_rcu(dev);
+                if (!in_dev)
+                        continue;
+
+                for_ifa(in_dev) {
+                        if (ifa->ifa_net_ns != net_ns)
+                               continue;
+                       if (addr == ifa->ifa_local ||
+                           addr == ifa->ifa_broadcast ||
+                           addr == (ifa->ifa_local & ifa->ifa_mask) ||
+                           addr == ((ifa->ifa_address & ifa->ifa_mask)|
+                                     ~ifa->ifa_mask)) {
+                               ret = 0;
+                               goto out;
+                       }
+                } endfor_ifa(in_dev);
+        }
+out:
+        read_unlock(&dev_base_lock);
+        rcu_read_unlock();
+
+       return ret;
+}
+
 #endif /* CONFIG_NET_NS */

-- 
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to