Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / ipv4 / ipvs / ip_vs_ctl.c
index 218d970..f28ec68 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/mutex.h>
 
 #include <net/ip.h>
+#include <net/route.h>
 #include <net/sock.h>
 
 #include <asm/uaccess.h>
@@ -42,7 +45,7 @@
 #include <net/ip_vs.h>
 
 /* semaphore for IPVS sockopts. And, [gs]etsockopt may sleep. */
-static DECLARE_MUTEX(__ip_vs_mutex);
+static DEFINE_MUTEX(__ip_vs_mutex);
 
 /* lock for service table */
 static DEFINE_RWLOCK(__ip_vs_svc_lock);
@@ -90,7 +93,8 @@ int ip_vs_get_debug_level(void)
 #endif
 
 /*
- *     update_defense_level is called from keventd and from sysctl.
+ *     update_defense_level is called from keventd and from sysctl,
+ *     so it needs to protect itself from softirqs
  */
 static void update_defense_level(void)
 {
@@ -110,6 +114,8 @@ static void update_defense_level(void)
 
        nomem = (availmem < sysctl_ip_vs_amemthresh);
 
+       local_bh_disable();
+
        /* drop_entry */
        spin_lock(&__ip_vs_dropentry_lock);
        switch (sysctl_ip_vs_drop_entry) {
@@ -206,6 +212,8 @@ static void update_defense_level(void)
        if (to_change >= 0)
                ip_vs_protocol_timeout_change(sysctl_ip_vs_secure_tcp>1);
        write_unlock(&__ip_vs_securetcp_lock);
+
+       local_bh_enable();
 }
 
 
@@ -442,7 +450,7 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __u32 vaddr, __u16 vport)
   out:
        read_unlock(&__ip_vs_svc_lock);
 
-       IP_VS_DBG(6, "lookup service: fwm %u %s %u.%u.%u.%u:%u %s\n",
+       IP_VS_DBG(9, "lookup service: fwm %u %s %u.%u.%u.%u:%u %s\n",
                  fwmark, ip_vs_proto_name(protocol),
                  NIPQUAD(vaddr), ntohs(vport),
                  svc?"hit":"not hit");
@@ -592,7 +600,7 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
         */
        list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
                IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
-                         "refcnt=%d\n",
+                         "dest->refcnt=%d\n",
                          dest->vfwmark,
                          NIPQUAD(dest->addr), ntohs(dest->port),
                          atomic_read(&dest->refcnt));
@@ -799,7 +807,7 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
        dest = ip_vs_trash_get_dest(svc, daddr, dport);
        if (dest != NULL) {
                IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
-                         "refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
+                         "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
                          NIPQUAD(daddr), ntohs(dport),
                          atomic_read(&dest->refcnt),
                          dest->vfwmark,
@@ -944,7 +952,8 @@ static void __ip_vs_del_dest(struct ip_vs_dest *dest)
                atomic_dec(&dest->svc->refcnt);
                kfree(dest);
        } else {
-               IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, refcnt=%d\n",
+               IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, "
+                         "dest->refcnt=%d\n",
                          NIPQUAD(dest->addr), ntohs(dest->port),
                          atomic_read(&dest->refcnt));
                list_add(&dest->n_list, &ip_vs_dest_trash);
@@ -1360,9 +1369,7 @@ proc_do_defense_mode(ctl_table *table, int write, struct file * filp,
                        /* Restore the correct value */
                        *valp = val;
                } else {
-                       local_bh_disable();
                        update_defense_level();
-                       local_bh_enable();
                }
        }
        return rc;
@@ -1595,7 +1602,7 @@ static ctl_table vs_table[] = {
        { .ctl_name = 0 }
 };
 
-static ctl_table ipv4_table[] = {
+static ctl_table ipvs_ipv4_table[] = {
        {
                .ctl_name       = NET_IPV4,
                .procname       = "ipv4",
@@ -1610,7 +1617,7 @@ static ctl_table vs_root_table[] = {
                .ctl_name       = CTL_NET,
                .procname       = "net",
                .mode           = 0555,
-               .child          = ipv4_table,
+               .child          = ipvs_ipv4_table,
        },
        { .ctl_name = 0 }
 };
@@ -1906,7 +1913,7 @@ static int ip_vs_set_timeout(struct ip_vs_timeout_user *u)
 #define DAEMON_ARG_LEN         (sizeof(struct ip_vs_daemon_user))
 #define MAX_ARG_LEN            SVCDEST_ARG_LEN
 
-static unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {
+static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {
        [SET_CMDID(IP_VS_SO_SET_ADD)]           = SERVICE_ARG_LEN,
        [SET_CMDID(IP_VS_SO_SET_EDIT)]          = SERVICE_ARG_LEN,
        [SET_CMDID(IP_VS_SO_SET_DEL)]           = SERVICE_ARG_LEN,
@@ -1944,7 +1951,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
        /* increase the module use count */
        ip_vs_use_count_inc();
 
-       if (down_interruptible(&__ip_vs_mutex)) {
+       if (mutex_lock_interruptible(&__ip_vs_mutex)) {
                ret = -ERESTARTSYS;
                goto out_dec;
        }
@@ -2035,7 +2042,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
                ip_vs_service_put(svc);
 
   out_unlock:
-       up(&__ip_vs_mutex);
+       mutex_unlock(&__ip_vs_mutex);
   out_dec:
        /* decrease the module use count */
        ip_vs_use_count_dec();
@@ -2059,7 +2066,7 @@ ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
        dst->addr = src->addr;
        dst->port = src->port;
        dst->fwmark = src->fwmark;
-       strcpy(dst->sched_name, src->scheduler->name);
+       strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
        dst->flags = src->flags;
        dst->timeout = src->timeout / HZ;
        dst->netmask = src->netmask;
@@ -2080,6 +2087,7 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
                list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
                        if (count >= get->num_services)
                                goto out;
+                       memset(&entry, 0, sizeof(entry));
                        ip_vs_copy_service(&entry, svc);
                        if (copy_to_user(&uptr->entrytable[count],
                                         &entry, sizeof(entry))) {
@@ -2094,6 +2102,7 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
                list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
                        if (count >= get->num_services)
                                goto out;
+                       memset(&entry, 0, sizeof(entry));
                        ip_vs_copy_service(&entry, svc);
                        if (copy_to_user(&uptr->entrytable[count],
                                         &entry, sizeof(entry))) {
@@ -2175,7 +2184,7 @@ __ip_vs_get_timeouts(struct ip_vs_timeout_user *u)
 #define GET_TIMEOUT_ARG_LEN    (sizeof(struct ip_vs_timeout_user))
 #define GET_DAEMON_ARG_LEN     (sizeof(struct ip_vs_daemon_user) * 2)
 
-static unsigned char get_arglen[GET_CMDID(IP_VS_SO_GET_MAX)+1] = {
+static const unsigned char get_arglen[GET_CMDID(IP_VS_SO_GET_MAX)+1] = {
        [GET_CMDID(IP_VS_SO_GET_VERSION)]       = 64,
        [GET_CMDID(IP_VS_SO_GET_INFO)]          = GET_INFO_ARG_LEN,
        [GET_CMDID(IP_VS_SO_GET_SERVICES)]      = GET_SERVICES_ARG_LEN,
@@ -2203,7 +2212,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        if (copy_from_user(arg, user, get_arglen[GET_CMDID(cmd)]) != 0)
                return -EFAULT;
 
-       if (down_interruptible(&__ip_vs_mutex))
+       if (mutex_lock_interruptible(&__ip_vs_mutex))
                return -ERESTARTSYS;
 
        switch (cmd) {
@@ -2304,12 +2313,12 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
                memset(&d, 0, sizeof(d));
                if (ip_vs_sync_state & IP_VS_STATE_MASTER) {
                        d[0].state = IP_VS_STATE_MASTER;
-                       strcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn);
+                       strlcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn, sizeof(d[0].mcast_ifn));
                        d[0].syncid = ip_vs_master_syncid;
                }
                if (ip_vs_sync_state & IP_VS_STATE_BACKUP) {
                        d[1].state = IP_VS_STATE_BACKUP;
-                       strcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn);
+                       strlcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn, sizeof(d[1].mcast_ifn));
                        d[1].syncid = ip_vs_backup_syncid;
                }
                if (copy_to_user(user, &d, sizeof(d)) != 0)
@@ -2322,7 +2331,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        }
 
   out:
-       up(&__ip_vs_mutex);
+       mutex_unlock(&__ip_vs_mutex);
        return ret;
 }