|
@@ -393,15 +393,11 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * this one is very careful, as it is the first function
|
|
|
- * to parse the userspace data
|
|
|
- */
|
|
|
static inline int
|
|
|
-ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|
|
+__ebt_verify_pointers(struct ebt_entry *e,
|
|
|
struct ebt_table_info *newinfo, char *base, char *limit,
|
|
|
- struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
|
|
|
- unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
|
|
|
+ struct ebt_entries **hook_entries,
|
|
|
+ unsigned int valid_hooks)
|
|
|
{
|
|
|
unsigned int offset = (char *)e - newinfo->entries;
|
|
|
size_t left = (limit - base) - offset;
|
|
@@ -416,8 +412,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|
|
if ((char *)hook_entries[i] == base + offset)
|
|
|
break;
|
|
|
}
|
|
|
- /* beginning of a new chain
|
|
|
- if i == NF_BR_NUMHOOKS it must be a user defined chain */
|
|
|
if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
|
|
|
if (e->bitmask != 0) {
|
|
|
/* we make userspace set this right,
|
|
@@ -426,6 +420,45 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|
|
"in distinguisher\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
+ if (left < sizeof(struct ebt_entries))
|
|
|
+ goto Esmall;
|
|
|
+ if (i != NF_BR_NUMHOOKS)
|
|
|
+ newinfo->hook_entry[i] = (struct ebt_entries *)e;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if (left < sizeof(struct ebt_entry))
|
|
|
+ goto Esmall;
|
|
|
+ if (left < e->next_offset)
|
|
|
+ goto Esmall;
|
|
|
+ return 0;
|
|
|
+
|
|
|
+Esmall:
|
|
|
+ BUGPRINT("entries_size too small\n");
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * this one is very careful, as it is the first function
|
|
|
+ * to parse the userspace data
|
|
|
+ */
|
|
|
+static inline int
|
|
|
+ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|
|
+ struct ebt_table_info *newinfo, char *base,
|
|
|
+ struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
|
|
|
+ unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
|
|
|
+{
|
|
|
+ unsigned int offset = (char *)e - newinfo->entries;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
|
|
|
+ if ((valid_hooks & (1 << i)) == 0)
|
|
|
+ continue;
|
|
|
+ if ((char *)hook_entries[i] == base + offset)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ /* beginning of a new chain
|
|
|
+ if i == NF_BR_NUMHOOKS it must be a user defined chain */
|
|
|
+ if (i != NF_BR_NUMHOOKS || !e->bitmask) {
|
|
|
/* this checks if the previous chain has as many entries
|
|
|
as it said it has */
|
|
|
if (*n != *cnt) {
|
|
@@ -433,9 +466,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|
|
"in the chain\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- /* before we look at the struct, be sure it is not too big */
|
|
|
- if (left < sizeof(struct ebt_entries))
|
|
|
- goto Esmall;
|
|
|
if (((struct ebt_entries *)e)->policy != EBT_DROP &&
|
|
|
((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
|
|
|
/* only RETURN from udc */
|
|
@@ -447,8 +477,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|
|
}
|
|
|
if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */
|
|
|
(*udc_cnt)++;
|
|
|
- else
|
|
|
- newinfo->hook_entry[i] = (struct ebt_entries *)e;
|
|
|
if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
|
|
|
BUGPRINT("counter_offset != totalcnt");
|
|
|
return -EINVAL;
|
|
@@ -458,8 +486,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|
|
return 0;
|
|
|
}
|
|
|
/* a plain old entry, heh */
|
|
|
- if (left < sizeof(struct ebt_entry))
|
|
|
- goto Esmall;
|
|
|
if (sizeof(struct ebt_entry) > e->watchers_offset ||
|
|
|
e->watchers_offset > e->target_offset ||
|
|
|
e->target_offset >= e->next_offset) {
|
|
@@ -471,16 +497,9 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|
|
BUGPRINT("target size too small\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- if (left < e->next_offset)
|
|
|
- goto Esmall;
|
|
|
-
|
|
|
(*cnt)++;
|
|
|
(*totalcnt)++;
|
|
|
return 0;
|
|
|
-
|
|
|
-Esmall:
|
|
|
- BUGPRINT("entries_size too small\n");
|
|
|
- return -EINVAL;
|
|
|
}
|
|
|
|
|
|
struct ebt_cl_stack
|
|
@@ -776,6 +795,12 @@ static int translate_table(struct ebt_replace *repl,
|
|
|
newinfo->entries_size = repl->entries_size;
|
|
|
newinfo->nentries = repl->nentries;
|
|
|
|
|
|
+ ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
|
|
|
+ __ebt_verify_pointers, newinfo, repl->entries,
|
|
|
+ repl->entries + repl->entries_size, repl->hook_entry, repl->valid_hooks);
|
|
|
+ if (ret != 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
/* do some early checkings and initialize some things */
|
|
|
i = 0; /* holds the expected nr. of entries for the chain */
|
|
|
j = 0; /* holds the up to now counted entries for the chain */
|
|
@@ -784,7 +809,7 @@ static int translate_table(struct ebt_replace *repl,
|
|
|
udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */
|
|
|
ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
|
|
|
ebt_check_entry_size_and_hooks, newinfo, repl->entries,
|
|
|
- repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k,
|
|
|
+ repl->hook_entry, &i, &j, &k,
|
|
|
&udc_cnt, repl->valid_hooks);
|
|
|
|
|
|
if (ret != 0)
|