Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb2ef25c authored by Al Viro's avatar Al Viro Committed by David S. Miller
Browse files

[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: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b6332e6c
Loading
Loading
Loading
Loading
+16 −7
Original line number Original line Diff line number Diff line
@@ -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