diff options
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 78 |
1 files changed, 41 insertions, 37 deletions
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index e79c0fbd9e89..2eba40f54233 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -393,48 +393,54 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, | |||
393 | return 0; | 393 | return 0; |
394 | } | 394 | } |
395 | 395 | ||
396 | static inline int | 396 | static int ebt_verify_pointers(struct ebt_replace *repl, |
397 | __ebt_verify_pointers(struct ebt_entry *e, | 397 | struct ebt_table_info *newinfo) |
398 | struct ebt_table_info *newinfo, char *base, char *limit, | ||
399 | struct ebt_entries **hook_entries, | ||
400 | unsigned int valid_hooks) | ||
401 | { | 398 | { |
402 | unsigned int offset = (char *)e - newinfo->entries; | 399 | unsigned int limit = repl->entries_size; |
403 | size_t left = (limit - base) - offset; | 400 | unsigned int valid_hooks = repl->valid_hooks; |
401 | unsigned int offset = 0; | ||
404 | int i; | 402 | int i; |
405 | 403 | ||
406 | if (left < sizeof(unsigned int)) | 404 | while (offset < limit) { |
407 | goto Esmall; | 405 | size_t left = limit - offset; |
406 | struct ebt_entry *e = (void *)newinfo->entries + offset; | ||
408 | 407 | ||
409 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { | 408 | if (left < sizeof(unsigned int)) |
410 | if ((valid_hooks & (1 << i)) == 0) | ||
411 | continue; | ||
412 | if ((char *)hook_entries[i] == base + offset) | ||
413 | break; | 409 | break; |
414 | } | 410 | |
415 | if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { | 411 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { |
416 | if (e->bitmask != 0) { | 412 | if ((valid_hooks & (1 << i)) == 0) |
417 | /* we make userspace set this right, | 413 | continue; |
418 | so there is no misunderstanding */ | 414 | if ((char *)repl->hook_entry[i] == repl->entries + offset) |
419 | BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set " | 415 | break; |
420 | "in distinguisher\n"); | ||
421 | return -EINVAL; | ||
422 | } | 416 | } |
423 | if (left < sizeof(struct ebt_entries)) | 417 | |
424 | goto Esmall; | 418 | if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { |
425 | if (i != NF_BR_NUMHOOKS) | 419 | if (e->bitmask != 0) { |
426 | newinfo->hook_entry[i] = (struct ebt_entries *)e; | 420 | /* we make userspace set this right, |
427 | return 0; | 421 | so there is no misunderstanding */ |
422 | BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set " | ||
423 | "in distinguisher\n"); | ||
424 | return -EINVAL; | ||
425 | } | ||
426 | if (i != NF_BR_NUMHOOKS) | ||
427 | newinfo->hook_entry[i] = (struct ebt_entries *)e; | ||
428 | if (left < sizeof(struct ebt_entries)) | ||
429 | break; | ||
430 | offset += sizeof(struct ebt_entries); | ||
431 | } else { | ||
432 | if (left < sizeof(struct ebt_entry)) | ||
433 | break; | ||
434 | if (left < e->next_offset) | ||
435 | break; | ||
436 | offset += e->next_offset; | ||
437 | } | ||
438 | } | ||
439 | if (offset != limit) { | ||
440 | BUGPRINT("entries_size too small\n"); | ||
441 | return -EINVAL; | ||
428 | } | 442 | } |
429 | if (left < sizeof(struct ebt_entry)) | ||
430 | goto Esmall; | ||
431 | if (left < e->next_offset) | ||
432 | goto Esmall; | ||
433 | return 0; | 443 | return 0; |
434 | |||
435 | Esmall: | ||
436 | BUGPRINT("entries_size too small\n"); | ||
437 | return -EINVAL; | ||
438 | } | 444 | } |
439 | 445 | ||
440 | /* | 446 | /* |
@@ -795,9 +801,7 @@ static int translate_table(struct ebt_replace *repl, | |||
795 | newinfo->entries_size = repl->entries_size; | 801 | newinfo->entries_size = repl->entries_size; |
796 | newinfo->nentries = repl->nentries; | 802 | newinfo->nentries = repl->nentries; |
797 | 803 | ||
798 | ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, | 804 | ret = ebt_verify_pointers(repl, newinfo); |
799 | __ebt_verify_pointers, newinfo, repl->entries, | ||
800 | repl->entries + repl->entries_size, repl->hook_entry, repl->valid_hooks); | ||
801 | if (ret != 0) | 805 | if (ret != 0) |
802 | return ret; | 806 | return ret; |
803 | 807 | ||