diff options
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 73 |
1 files changed, 49 insertions, 24 deletions
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 136ed7d4bd73..e79c0fbd9e89 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -393,15 +393,11 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, | |||
393 | return 0; | 393 | return 0; |
394 | } | 394 | } |
395 | 395 | ||
396 | /* | ||
397 | * this one is very careful, as it is the first function | ||
398 | * to parse the userspace data | ||
399 | */ | ||
400 | static inline int | 396 | static inline int |
401 | ebt_check_entry_size_and_hooks(struct ebt_entry *e, | 397 | __ebt_verify_pointers(struct ebt_entry *e, |
402 | struct ebt_table_info *newinfo, char *base, char *limit, | 398 | struct ebt_table_info *newinfo, char *base, char *limit, |
403 | struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt, | 399 | struct ebt_entries **hook_entries, |
404 | unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks) | 400 | unsigned int valid_hooks) |
405 | { | 401 | { |
406 | unsigned int offset = (char *)e - newinfo->entries; | 402 | unsigned int offset = (char *)e - newinfo->entries; |
407 | size_t left = (limit - base) - offset; | 403 | size_t left = (limit - base) - offset; |
@@ -416,8 +412,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e, | |||
416 | if ((char *)hook_entries[i] == base + offset) | 412 | if ((char *)hook_entries[i] == base + offset) |
417 | break; | 413 | break; |
418 | } | 414 | } |
419 | /* beginning of a new chain | ||
420 | if i == NF_BR_NUMHOOKS it must be a user defined chain */ | ||
421 | if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { | 415 | if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) { |
422 | if (e->bitmask != 0) { | 416 | if (e->bitmask != 0) { |
423 | /* we make userspace set this right, | 417 | /* we make userspace set this right, |
@@ -426,6 +420,45 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e, | |||
426 | "in distinguisher\n"); | 420 | "in distinguisher\n"); |
427 | return -EINVAL; | 421 | return -EINVAL; |
428 | } | 422 | } |
423 | if (left < sizeof(struct ebt_entries)) | ||
424 | goto Esmall; | ||
425 | if (i != NF_BR_NUMHOOKS) | ||
426 | newinfo->hook_entry[i] = (struct ebt_entries *)e; | ||
427 | return 0; | ||
428 | } | ||
429 | if (left < sizeof(struct ebt_entry)) | ||
430 | goto Esmall; | ||
431 | if (left < e->next_offset) | ||
432 | goto Esmall; | ||
433 | return 0; | ||
434 | |||
435 | Esmall: | ||
436 | BUGPRINT("entries_size too small\n"); | ||
437 | return -EINVAL; | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * this one is very careful, as it is the first function | ||
442 | * to parse the userspace data | ||
443 | */ | ||
444 | static inline int | ||
445 | ebt_check_entry_size_and_hooks(struct ebt_entry *e, | ||
446 | struct ebt_table_info *newinfo, char *base, | ||
447 | struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt, | ||
448 | unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks) | ||
449 | { | ||
450 | unsigned int offset = (char *)e - newinfo->entries; | ||
451 | int i; | ||
452 | |||
453 | for (i = 0; i < NF_BR_NUMHOOKS; i++) { | ||
454 | if ((valid_hooks & (1 << i)) == 0) | ||
455 | continue; | ||
456 | if ((char *)hook_entries[i] == base + offset) | ||
457 | break; | ||
458 | } | ||
459 | /* beginning of a new chain | ||
460 | if i == NF_BR_NUMHOOKS it must be a user defined chain */ | ||
461 | if (i != NF_BR_NUMHOOKS || !e->bitmask) { | ||
429 | /* this checks if the previous chain has as many entries | 462 | /* this checks if the previous chain has as many entries |
430 | as it said it has */ | 463 | as it said it has */ |
431 | if (*n != *cnt) { | 464 | if (*n != *cnt) { |
@@ -433,9 +466,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e, | |||
433 | "in the chain\n"); | 466 | "in the chain\n"); |
434 | return -EINVAL; | 467 | return -EINVAL; |
435 | } | 468 | } |
436 | /* before we look at the struct, be sure it is not too big */ | ||
437 | if (left < sizeof(struct ebt_entries)) | ||
438 | goto Esmall; | ||
439 | if (((struct ebt_entries *)e)->policy != EBT_DROP && | 469 | if (((struct ebt_entries *)e)->policy != EBT_DROP && |
440 | ((struct ebt_entries *)e)->policy != EBT_ACCEPT) { | 470 | ((struct ebt_entries *)e)->policy != EBT_ACCEPT) { |
441 | /* only RETURN from udc */ | 471 | /* only RETURN from udc */ |
@@ -447,8 +477,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e, | |||
447 | } | 477 | } |
448 | if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */ | 478 | if (i == NF_BR_NUMHOOKS) /* it's a user defined chain */ |
449 | (*udc_cnt)++; | 479 | (*udc_cnt)++; |
450 | else | ||
451 | newinfo->hook_entry[i] = (struct ebt_entries *)e; | ||
452 | if (((struct ebt_entries *)e)->counter_offset != *totalcnt) { | 480 | if (((struct ebt_entries *)e)->counter_offset != *totalcnt) { |
453 | BUGPRINT("counter_offset != totalcnt"); | 481 | BUGPRINT("counter_offset != totalcnt"); |
454 | return -EINVAL; | 482 | return -EINVAL; |
@@ -458,8 +486,6 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e, | |||
458 | return 0; | 486 | return 0; |
459 | } | 487 | } |
460 | /* a plain old entry, heh */ | 488 | /* a plain old entry, heh */ |
461 | if (left < sizeof(struct ebt_entry)) | ||
462 | goto Esmall; | ||
463 | if (sizeof(struct ebt_entry) > e->watchers_offset || | 489 | if (sizeof(struct ebt_entry) > e->watchers_offset || |
464 | e->watchers_offset > e->target_offset || | 490 | e->watchers_offset > e->target_offset || |
465 | e->target_offset >= e->next_offset) { | 491 | e->target_offset >= e->next_offset) { |
@@ -471,16 +497,9 @@ ebt_check_entry_size_and_hooks(struct ebt_entry *e, | |||
471 | BUGPRINT("target size too small\n"); | 497 | BUGPRINT("target size too small\n"); |
472 | return -EINVAL; | 498 | return -EINVAL; |
473 | } | 499 | } |
474 | if (left < e->next_offset) | ||
475 | goto Esmall; | ||
476 | |||
477 | (*cnt)++; | 500 | (*cnt)++; |
478 | (*totalcnt)++; | 501 | (*totalcnt)++; |
479 | return 0; | 502 | return 0; |
480 | |||
481 | Esmall: | ||
482 | BUGPRINT("entries_size too small\n"); | ||
483 | return -EINVAL; | ||
484 | } | 503 | } |
485 | 504 | ||
486 | struct ebt_cl_stack | 505 | struct ebt_cl_stack |
@@ -776,6 +795,12 @@ static int translate_table(struct ebt_replace *repl, | |||
776 | newinfo->entries_size = repl->entries_size; | 795 | newinfo->entries_size = repl->entries_size; |
777 | newinfo->nentries = repl->nentries; | 796 | newinfo->nentries = repl->nentries; |
778 | 797 | ||
798 | ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, | ||
799 | __ebt_verify_pointers, newinfo, repl->entries, | ||
800 | repl->entries + repl->entries_size, repl->hook_entry, repl->valid_hooks); | ||
801 | if (ret != 0) | ||
802 | return ret; | ||
803 | |||
779 | /* do some early checkings and initialize some things */ | 804 | /* do some early checkings and initialize some things */ |
780 | i = 0; /* holds the expected nr. of entries for the chain */ | 805 | i = 0; /* holds the expected nr. of entries for the chain */ |
781 | j = 0; /* holds the up to now counted entries for the chain */ | 806 | j = 0; /* holds the up to now counted entries for the chain */ |
@@ -784,7 +809,7 @@ static int translate_table(struct ebt_replace *repl, | |||
784 | udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */ | 809 | udc_cnt = 0; /* will hold the nr. of user defined chains (udc) */ |
785 | ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, | 810 | ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, |
786 | ebt_check_entry_size_and_hooks, newinfo, repl->entries, | 811 | ebt_check_entry_size_and_hooks, newinfo, repl->entries, |
787 | repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k, | 812 | repl->hook_entry, &i, &j, &k, |
788 | &udc_cnt, repl->valid_hooks); | 813 | &udc_cnt, repl->valid_hooks); |
789 | 814 | ||
790 | if (ret != 0) | 815 | if (ret != 0) |