[EBTABLES]: Fix wraparounds in ebt_entries verification.
We need to verify that a) we are not too close to the end of buffer to dereference b) next entry we'll be checking won't be _before_ our While we are at it, don't subtract unrelated pointers... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -401,13 +401,17 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|||||||
struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
|
struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
|
||||||
unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
|
unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
|
||||||
{
|
{
|
||||||
|
unsigned int offset = (char *)e - newinfo->entries;
|
||||||
|
size_t left = (limit - base) - offset;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (left < sizeof(unsigned int))
|
||||||
|
goto Esmall;
|
||||||
|
|
||||||
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
|
for (i = 0; i < NF_BR_NUMHOOKS; i++) {
|
||||||
if ((valid_hooks & (1 << i)) == 0)
|
if ((valid_hooks & (1 << i)) == 0)
|
||||||
continue;
|
continue;
|
||||||
if ( (char *)hook_entries[i] - base ==
|
if ((char *)hook_entries[i] == base + offset)
|
||||||
(char *)e - newinfo->entries)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* beginning of a new chain
|
/* beginning of a new chain
|
||||||
@@ -428,11 +432,8 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/* before we look at the struct, be sure it is not too big */
|
/* before we look at the struct, be sure it is not too big */
|
||||||
if ((char *)hook_entries[i] + sizeof(struct ebt_entries)
|
if (left < sizeof(struct ebt_entries))
|
||||||
> limit) {
|
goto Esmall;
|
||||||
BUGPRINT("entries_size too small\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (((struct ebt_entries *)e)->policy != EBT_DROP &&
|
if (((struct ebt_entries *)e)->policy != EBT_DROP &&
|
||||||
((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
|
((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
|
||||||
/* only RETURN from udc */
|
/* only RETURN from udc */
|
||||||
@@ -455,6 +456,8 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* a plain old entry, heh */
|
/* a plain old entry, heh */
|
||||||
|
if (left < sizeof(struct ebt_entry))
|
||||||
|
goto Esmall;
|
||||||
if (sizeof(struct ebt_entry) > e->watchers_offset ||
|
if (sizeof(struct ebt_entry) > e->watchers_offset ||
|
||||||
e->watchers_offset > e->target_offset ||
|
e->watchers_offset > e->target_offset ||
|
||||||
e->target_offset >= e->next_offset) {
|
e->target_offset >= e->next_offset) {
|
||||||
@@ -466,10 +469,16 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e,
|
|||||||
BUGPRINT("target size too small\n");
|
BUGPRINT("target size too small\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
if (left < e->next_offset)
|
||||||
|
goto Esmall;
|
||||||
|
|
||||||
(*cnt)++;
|
(*cnt)++;
|
||||||
(*totalcnt)++;
|
(*totalcnt)++;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
Esmall:
|
||||||
|
BUGPRINT("entries_size too small\n");
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ebt_cl_stack
|
struct ebt_cl_stack
|
||||||
|
Reference in New Issue
Block a user