return 0;
}
-static inline int
-__ebt_verify_pointers(struct ebt_entry *e,
- struct ebt_table_info *newinfo, char *base, char *limit,
- struct ebt_entries **hook_entries,
- unsigned int valid_hooks)
+static int ebt_verify_pointers(struct ebt_replace *repl,
+ struct ebt_table_info *newinfo)
{
- unsigned int offset = (char *)e - newinfo->entries;
- size_t left = (limit - base) - offset;
+ unsigned int limit = repl->entries_size;
+ unsigned int valid_hooks = repl->valid_hooks;
+ unsigned int offset = 0;
int i;
- if (left < sizeof(unsigned int))
- goto Esmall;
+ for (i = 0; i < NF_BR_NUMHOOKS; i++)
+ newinfo->hook_entry[i] = NULL;
- for (i = 0; i < NF_BR_NUMHOOKS; i++) {
- if ((valid_hooks & (1 << i)) == 0)
- continue;
- if ((char *)hook_entries[i] == base + offset)
+ newinfo->entries_size = repl->entries_size;
+ newinfo->nentries = repl->nentries;
+
+ while (offset < limit) {
+ size_t left = limit - offset;
+ struct ebt_entry *e = (void *)newinfo->entries + offset;
+
+ if (left < sizeof(unsigned int))
break;
+
+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+ if ((valid_hooks & (1 << i)) == 0)
+ continue;
+ if ((char *)repl->hook_entry[i] == repl->entries + offset)
+ break;
+ }
+
+ if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
+ if (e->bitmask != 0) {
+ /* we make userspace set this right,
+ so there is no misunderstanding */
+ BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
+ "in distinguisher\n");
+ return -EINVAL;
+ }
+ if (i != NF_BR_NUMHOOKS)
+ newinfo->hook_entry[i] = (struct ebt_entries *)e;
+ if (left < sizeof(struct ebt_entries))
+ break;
+ offset += sizeof(struct ebt_entries);
+ } else {
+ if (left < sizeof(struct ebt_entry))
+ break;
+ if (left < e->next_offset)
+ break;
+ offset += e->next_offset;
+ }
+ }
+ if (offset != limit) {
+ BUGPRINT("entries_size too small\n");
+ return -EINVAL;
}
- if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
- if (e->bitmask != 0) {
- /* we make userspace set this right,
- so there is no misunderstanding */
- BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
- "in distinguisher\n");
+
+ /* check if all valid hooks have a chain */
+ for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+ if (!newinfo->hook_entry[i] &&
+ (valid_hooks & (1 << i))) {
+ BUGPRINT("Valid hook without chain\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;
}
/*
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 && !(repl->valid_hooks & (1 << i)))
+ while (i < NF_BR_NUMHOOKS && !newinfo->hook_entry[i])
i++;
if (i == NF_BR_NUMHOOKS) {
BUGPRINT("No valid hooks specified\n");
return -EINVAL;
}
- if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) {
+ if (newinfo->hook_entry[i] != (struct ebt_entries *)newinfo->entries) {
BUGPRINT("Chains don't start at beginning\n");
return -EINVAL;
}
/* make sure chains are ordered after each other in same order
as their corresponding hooks */
for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
- if (!(repl->valid_hooks & (1 << j)))
+ if (!newinfo->hook_entry[j])
continue;
- if ( repl->hook_entry[j] <= repl->hook_entry[i] ) {
+ if (newinfo->hook_entry[j] <= newinfo->hook_entry[i]) {
BUGPRINT("Hook order must be followed\n");
return -EINVAL;
}
i = j;
}
- for (i = 0; i < NF_BR_NUMHOOKS; i++)
- newinfo->hook_entry[i] = NULL;
-
- 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 */
return -EINVAL;
}
- /* check if all valid hooks have a chain */
- for (i = 0; i < NF_BR_NUMHOOKS; i++) {
- if (newinfo->hook_entry[i] == NULL &&
- (repl->valid_hooks & (1 << i))) {
- BUGPRINT("Valid hook without chain\n");
- return -EINVAL;
- }
- }
-
/* get the location of the udc, put them in an array
while we're at it, allocate the chainstack */
if (udc_cnt) {
/* Check for loops */
for (i = 0; i < NF_BR_NUMHOOKS; i++)
- if (repl->valid_hooks & (1 << i))
+ if (newinfo->hook_entry[i])
if (check_chainloops(newinfo->hook_entry[i],
cl_s, udc_cnt, i, newinfo->entries)) {
vfree(cl_s);