Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/agpgart
[pandora-kernel.git] / net / bridge / netfilter / ebtables.c
index 4d1cf14..6c84ccb 100644 (file)
@@ -417,7 +417,8 @@ static int ebt_verify_pointers(struct ebt_replace *repl,
                for (i = 0; i < NF_BR_NUMHOOKS; i++) {
                        if ((valid_hooks & (1 << i)) == 0)
                                continue;
-                       if ((char *)repl->hook_entry[i] == repl->entries + offset)
+                       if ((char __user *)repl->hook_entry[i] ==
+                            repl->entries + offset)
                                break;
                }
 
@@ -603,13 +604,13 @@ ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
 
 static inline int
 ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
-   const char *name, unsigned int *cnt, unsigned int valid_hooks,
+   const char *name, unsigned int *cnt,
    struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
 {
        struct ebt_entry_target *t;
        struct ebt_target *target;
        unsigned int i, j, hook = 0, hookmask = 0;
-       size_t gap = e->next_offset - e->target_offset;
+       size_t gap;
        int ret;
 
        /* don't mess with the struct ebt_entries */
@@ -630,7 +631,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
        }
        /* what hook do we belong to? */
        for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-               if ((valid_hooks & (1 << i)) == 0)
+               if (!newinfo->hook_entry[i])
                        continue;
                if ((char *)newinfo->hook_entry[i] < (char *)e)
                        hook = i;
@@ -659,6 +660,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
        if (ret != 0)
                goto cleanup_watchers;
        t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
+       gap = e->next_offset - e->target_offset;
        target = find_target_lock(t->u.name, &ret, &ebt_mutex);
        if (!target)
                goto cleanup_watchers;
@@ -774,17 +776,12 @@ letscontinue:
 }
 
 /* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
-static int translate_table(struct ebt_replace *repl,
-   struct ebt_table_info *newinfo)
+static int translate_table(char *name, struct ebt_table_info *newinfo)
 {
        unsigned int i, j, k, udc_cnt;
        int ret;
        struct ebt_cl_stack *cl_s = NULL; /* used in the checking for chain loops */
 
-       ret = ebt_verify_pointers(repl, newinfo);
-       if (ret != 0)
-               return ret;
-
        i = 0;
        while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
                i++;
@@ -889,8 +886,7 @@ static int translate_table(struct ebt_replace *repl,
        /* used to know what we need to clean up if something goes wrong */
        i = 0;
        ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-          ebt_check_entry, newinfo, repl->name, &i, repl->valid_hooks,
-          cl_s, udc_cnt);
+          ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
        if (ret != 0) {
                EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
                   ebt_cleanup_entry, &i);
@@ -987,7 +983,11 @@ static int do_replace(void __user *user, unsigned int len)
 
        /* this can get initialized by translate_table() */
        newinfo->chainstack = NULL;
-       ret = translate_table(&tmp, newinfo);
+       ret = ebt_verify_pointers(&tmp, newinfo);
+       if (ret != 0)
+               goto free_counterstmp;
+
+       ret = translate_table(tmp.name, newinfo);
 
        if (ret != 0)
                goto free_counterstmp;
@@ -1158,35 +1158,47 @@ int ebt_register_table(struct ebt_table *table)
 {
        struct ebt_table_info *newinfo;
        struct ebt_table *t;
+       struct ebt_replace_kernel *repl;
        int ret, i, countersize;
+       void *p;
 
-       if (!table || !table->table ||!table->table->entries ||
-           table->table->entries_size == 0 ||
-           table->table->counters || table->private) {
+       if (!table || !(repl = table->table) || !repl->entries ||
+           repl->entries_size == 0 ||
+           repl->counters || table->private) {
                BUGPRINT("Bad table data for ebt_register_table!!!\n");
                return -EINVAL;
        }
 
-       countersize = COUNTER_OFFSET(table->table->nentries) *
+       countersize = COUNTER_OFFSET(repl->nentries) *
                                        (highest_possible_processor_id()+1);
        newinfo = vmalloc(sizeof(*newinfo) + countersize);
        ret = -ENOMEM;
        if (!newinfo)
                return -ENOMEM;
 
-       newinfo->entries = vmalloc(table->table->entries_size);
-       if (!(newinfo->entries))
+       p = vmalloc(repl->entries_size);
+       if (!p)
                goto free_newinfo;
 
-       memcpy(newinfo->entries, table->table->entries,
-          table->table->entries_size);
+       memcpy(p, repl->entries, repl->entries_size);
+       newinfo->entries = p;
+
+       newinfo->entries_size = repl->entries_size;
+       newinfo->nentries = repl->nentries;
 
        if (countersize)
                memset(newinfo->counters, 0, countersize);
 
        /* fill in newinfo and parse the entries */
        newinfo->chainstack = NULL;
-       ret = translate_table(table->table, newinfo);
+       for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+               if ((repl->valid_hooks & (1 << i)) == 0)
+                       newinfo->hook_entry[i] = NULL;
+               else
+                       newinfo->hook_entry[i] = p +
+                               ((char *)repl->hook_entry[i] - repl->entries);
+       }
+       ret = translate_table(repl->name, newinfo);
        if (ret != 0) {
                BUGPRINT("Translate_table failed\n");
                goto free_chainstack;
@@ -1310,33 +1322,33 @@ free_tmp:
 }
 
 static inline int ebt_make_matchname(struct ebt_entry_match *m,
-   char *base, char *ubase)
+   char *base, char __user *ubase)
 {
-       char *hlp = ubase - base + (char *)m;
+       char __user *hlp = ubase + ((char *)m - base);
        if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
                return -EFAULT;
        return 0;
 }
 
 static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
-   char *base, char *ubase)
+   char *base, char __user *ubase)
 {
-       char *hlp = ubase - base + (char *)w;
+       char __user *hlp = ubase + ((char *)w - base);
        if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
                return -EFAULT;
        return 0;
 }
 
-static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase)
+static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
 {
        int ret;
-       char *hlp;
+       char __user *hlp;
        struct ebt_entry_target *t;
 
        if (e->bitmask == 0)
                return 0;
 
-       hlp = ubase - base + (char *)e + e->target_offset;
+       hlp = ubase + (((char *)e + e->target_offset) - base);
        t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
        
        ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);