vserver 1.9.3
[linux-2.6.git] / net / ipv4 / netfilter / ip_tables.c
index 1c12071..8da90bd 100644 (file)
@@ -61,7 +61,6 @@ do {                                                          \
 #endif
 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
-/* Mutex protects lists (only traversed in user context). */
 static DECLARE_MUTEX(ipt_mutex);
 
 /* Must have mutex */
@@ -418,7 +417,7 @@ find_inlist_lock_noload(struct list_head *head,
 {
        void *ret;
 
-#if 0
+#if 0 
        duprintf("find_inlist: searching for `%s' in %s.\n",
                 name, head == &ipt_target ? "ipt_target"
                 : head == &ipt_match ? "ipt_match"
@@ -461,7 +460,7 @@ find_inlist_lock(struct list_head *head,
 #endif
 
 static inline struct ipt_table *
-find_table_lock(const char *name, int *error, struct semaphore *mutex)
+ipt_find_table_lock(const char *name, int *error, struct semaphore *mutex)
 {
        return find_inlist_lock(&ipt_tables, name, "iptable_", error, mutex);
 }
@@ -472,8 +471,8 @@ find_match_lock(const char *name, int *error, struct semaphore *mutex)
        return find_inlist_lock(&ipt_match, name, "ipt_", error, mutex);
 }
 
-static inline struct ipt_target *
-find_target_lock(const char *name, int *error, struct semaphore *mutex)
+struct ipt_target *
+ipt_find_target_lock(const char *name, int *error, struct semaphore *mutex)
 {
        return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex);
 }
@@ -688,7 +687,7 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size,
                goto cleanup_matches;
 
        t = ipt_get_target(e);
-       target = find_target_lock(t->u.user.name, &ret, &ipt_mutex);
+       target = ipt_find_target_lock(t->u.user.name, &ret, &ipt_mutex);
        if (!target) {
                duprintf("check_entry: `%s' not found\n", t->u.user.name);
                goto cleanup_matches;
@@ -942,7 +941,7 @@ get_counters(const struct ipt_table_info *t,
 static int
 copy_entries_to_user(unsigned int total_size,
                     struct ipt_table *table,
-                    void *userptr)
+                    void __user *userptr)
 {
        unsigned int off, num, countersize;
        struct ipt_entry *e;
@@ -1020,12 +1019,12 @@ copy_entries_to_user(unsigned int total_size,
 
 static int
 get_entries(const struct ipt_get_entries *entries,
-           struct ipt_get_entries *uptr)
+           struct ipt_get_entries __user *uptr)
 {
        int ret;
        struct ipt_table *t;
 
-       t = find_table_lock(entries->name, &ret, &ipt_mutex);
+       t = ipt_find_table_lock(entries->name, &ret, &ipt_mutex);
        if (t) {
                duprintf("t->private->number = %u\n",
                         t->private->number);
@@ -1047,7 +1046,7 @@ get_entries(const struct ipt_get_entries *entries,
 }
 
 static int
-do_replace(void *user, unsigned int len)
+do_replace(void __user *user, unsigned int len)
 {
        int ret;
        struct ipt_replace tmp;
@@ -1092,7 +1091,7 @@ do_replace(void *user, unsigned int len)
 
        duprintf("ip_tables: Translated table\n");
 
-       t = find_table_lock(tmp.name, &ret, &ipt_mutex);
+       t = ipt_find_table_lock(tmp.name, &ret, &ipt_mutex);
        if (!t)
                goto free_newinfo_counters_untrans;
 
@@ -1173,7 +1172,7 @@ add_counter_to_entry(struct ipt_entry *e,
 }
 
 static int
-do_add_counters(void *user, unsigned int len)
+do_add_counters(void __user *user, unsigned int len)
 {
        unsigned int i;
        struct ipt_counters_info tmp, *paddc;
@@ -1195,7 +1194,7 @@ do_add_counters(void *user, unsigned int len)
                goto free;
        }
 
-       t = find_table_lock(tmp.name, &ret, &ipt_mutex);
+       t = ipt_find_table_lock(tmp.name, &ret, &ipt_mutex);
        if (!t)
                goto free;
 
@@ -1221,7 +1220,7 @@ do_add_counters(void *user, unsigned int len)
 }
 
 static int
-do_ipt_set_ctl(struct sock *sk,        int cmd, void *user, unsigned int len)
+do_ipt_set_ctl(struct sock *sk,        int cmd, void __user *user, unsigned int len)
 {
        int ret;
 
@@ -1246,7 +1245,7 @@ do_ipt_set_ctl(struct sock *sk,   int cmd, void *user, unsigned int len)
 }
 
 static int
-do_ipt_get_ctl(struct sock *sk, int cmd, void *user, int *len)
+do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 {
        int ret;
 
@@ -1270,7 +1269,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void *user, int *len)
                        break;
                }
                name[IPT_TABLE_MAXNAMELEN-1] = '\0';
-               t = find_table_lock(name, &ret, &ipt_mutex);
+               t = ipt_find_table_lock(name, &ret, &ipt_mutex);
                if (t) {
                        struct ipt_getinfo info;
 
@@ -1461,21 +1460,27 @@ tcp_find_option(u_int8_t option,
                int *hotdrop)
 {
        /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
-       char opt[60 - sizeof(struct tcphdr)];
+       u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
        unsigned int i;
 
        duprintf("tcp_match: finding option\n");
+
+       if (!optlen)
+               return invert;
+
        /* If we don't have the whole header, drop packet. */
-       if (skb_copy_bits(skb, skb->nh.iph->ihl*4 + sizeof(struct tcphdr),
-                         opt, optlen) < 0) {
+       op = skb_header_pointer(skb,
+                               skb->nh.iph->ihl*4 + sizeof(struct tcphdr),
+                               optlen, _opt);
+       if (op == NULL) {
                *hotdrop = 1;
                return 0;
        }
 
        for (i = 0; i < optlen; ) {
-               if (opt[i] == option) return !invert;
-               if (opt[i] < 2) i++;
-               else i += opt[i+1]?:1;
+               if (op[i] == option) return !invert;
+               if (op[i] < 2) i++;
+               else i += op[i+1]?:1;
        }
 
        return invert;
@@ -1489,7 +1494,7 @@ tcp_match(const struct sk_buff *skb,
          int offset,
          int *hotdrop)
 {
-       struct tcphdr tcph;
+       struct tcphdr _tcph, *th;
        const struct ipt_tcp *tcpinfo = matchinfo;
 
        if (offset) {
@@ -1509,7 +1514,9 @@ tcp_match(const struct sk_buff *skb,
 
 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
 
-       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0) {
+       th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+                               sizeof(_tcph), &_tcph);
+       if (th == NULL) {
                /* We've been asked to examine this packet, and we
                   can't.  Hence, no choice but to drop. */
                duprintf("Dropping evil TCP offset=0 tinygram.\n");
@@ -1518,23 +1525,24 @@ tcp_match(const struct sk_buff *skb,
        }
 
        if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
-                       ntohs(tcph.source),
+                       ntohs(th->source),
                        !!(tcpinfo->invflags & IPT_TCP_INV_SRCPT)))
                return 0;
        if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
-                       ntohs(tcph.dest),
+                       ntohs(th->dest),
                        !!(tcpinfo->invflags & IPT_TCP_INV_DSTPT)))
                return 0;
-       if (!FWINVTCP((((unsigned char *)&tcph)[13] & tcpinfo->flg_mask)
+       if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
                      == tcpinfo->flg_cmp,
                      IPT_TCP_INV_FLAGS))
                return 0;
        if (tcpinfo->option) {
-               if (tcph.doff * 4 < sizeof(tcph)) {
+               if (th->doff * 4 < sizeof(_tcph)) {
                        *hotdrop = 1;
                        return 0;
                }
-               if (!tcp_find_option(tcpinfo->option, skb, tcph.doff*4 - sizeof(tcph),
+               if (!tcp_find_option(tcpinfo->option, skb,
+                                    th->doff*4 - sizeof(_tcph),
                                     tcpinfo->invflags & IPT_TCP_INV_OPTION,
                                     hotdrop))
                        return 0;
@@ -1567,14 +1575,16 @@ udp_match(const struct sk_buff *skb,
          int offset,
          int *hotdrop)
 {
-       struct udphdr udph;
+       struct udphdr _udph, *uh;
        const struct ipt_udp *udpinfo = matchinfo;
 
        /* Must not be a fragment. */
        if (offset)
                return 0;
 
-       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0) {
+       uh = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+                               sizeof(_udph), &_udph);
+       if (uh == NULL) {
                /* We've been asked to examine this packet, and we
                   can't.  Hence, no choice but to drop. */
                duprintf("Dropping evil UDP tinygram.\n");
@@ -1583,10 +1593,10 @@ udp_match(const struct sk_buff *skb,
        }
 
        return port_match(udpinfo->spts[0], udpinfo->spts[1],
-                         ntohs(udph.source),
+                         ntohs(uh->source),
                          !!(udpinfo->invflags & IPT_UDP_INV_SRCPT))
                && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
-                             ntohs(udph.dest),
+                             ntohs(uh->dest),
                              !!(udpinfo->invflags & IPT_UDP_INV_DSTPT));
 }
 
@@ -1638,16 +1648,19 @@ icmp_match(const struct sk_buff *skb,
           int offset,
           int *hotdrop)
 {
-       struct icmphdr icmph;
+       struct icmphdr _icmph, *ic;
        const struct ipt_icmp *icmpinfo = matchinfo;
 
        /* Must not be a fragment. */
        if (offset)
                return 0;
 
-       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &icmph, sizeof(icmph)) < 0){
+       ic = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+                               sizeof(_icmph), &_icmph);
+       if (ic == NULL) {
                /* We've been asked to examine this packet, and we
-                  can't.  Hence, no choice but to drop. */
+                * can't.  Hence, no choice but to drop.
+                */
                duprintf("Dropping evil ICMP tinygram.\n");
                *hotdrop = 1;
                return 0;
@@ -1656,7 +1669,7 @@ icmp_match(const struct sk_buff *skb,
        return icmp_type_code_match(icmpinfo->type,
                                    icmpinfo->code[0],
                                    icmpinfo->code[1],
-                                   icmph.type, icmph.code,
+                                   ic->type, ic->code,
                                    !!(icmpinfo->invflags&IPT_ICMP_INV));
 }
 
@@ -1734,6 +1747,15 @@ static inline int print_name(const char *i,
        return 0;
 }
 
+static inline int print_target(const struct ipt_target *t,
+                               off_t start_offset, char *buffer, int length,
+                               off_t *pos, unsigned int *count)
+{
+       if (t == &ipt_standard_target || t == &ipt_error_target)
+               return 0;
+       return print_name((char *)t, start_offset, buffer, length, pos, count);
+}
+
 static int ipt_get_tables(char *buffer, char **start, off_t offset, int length)
 {
        off_t pos = 0;
@@ -1760,7 +1782,7 @@ static int ipt_get_targets(char *buffer, char **start, off_t offset, int length)
        if (down_interruptible(&ipt_mutex) != 0)
                return 0;
 
-       LIST_FIND(&ipt_target, print_name, void *,
+       LIST_FIND(&ipt_target, print_target, struct ipt_target *,
                  offset, buffer, length, &pos, &count);
        
        up(&ipt_mutex);
@@ -1855,6 +1877,7 @@ EXPORT_SYMBOL(ipt_unregister_match);
 EXPORT_SYMBOL(ipt_do_table);
 EXPORT_SYMBOL(ipt_register_target);
 EXPORT_SYMBOL(ipt_unregister_target);
+EXPORT_SYMBOL(ipt_find_target_lock);
 
 module_init(init);
 module_exit(fini);