aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bridge/netfilter/ebtables.c78
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
396static inline int 396static 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
435Esmall:
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