diff options
| author | David S. Miller <davem@davemloft.net> | 2010-02-24 21:23:37 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-02-24 21:23:37 -0500 |
| commit | 54831a83bfe656c4c54e287c734c6b0ccaa3719b (patch) | |
| tree | abd5bef16d1a6011f629a36d4e245a2ed4f3df3c | |
| parent | fb977e2ca607a7e74946a1de798f474d1b80b9d6 (diff) | |
| parent | 0f234214d15fa914436d304ecf5c3e43449e79f9 (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
| -rw-r--r-- | include/linux/netfilter/x_tables.h | 17 | ||||
| -rw-r--r-- | include/linux/netfilter_arp/arp_tables.h | 10 | ||||
| -rw-r--r-- | include/linux/netfilter_ipv4/ip_tables.h | 15 | ||||
| -rw-r--r-- | include/linux/netfilter_ipv6/ip6_tables.h | 14 | ||||
| -rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 301 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 436 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 436 | ||||
| -rw-r--r-- | net/ipv6/netfilter/nf_conntrack_reasm.c | 8 | ||||
| -rw-r--r-- | net/netfilter/xt_TCPMSS.c | 12 | ||||
| -rw-r--r-- | net/netfilter/xt_recent.c | 4 |
10 files changed, 597 insertions, 656 deletions
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index a18119fb88f0..84c7c928e9eb 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h | |||
| @@ -120,6 +120,7 @@ struct xt_counters_info { | |||
| 120 | 120 | ||
| 121 | #define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */ | 121 | #define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */ |
| 122 | 122 | ||
| 123 | #ifndef __KERNEL__ | ||
| 123 | /* fn returns 0 to continue iteration */ | 124 | /* fn returns 0 to continue iteration */ |
| 124 | #define XT_MATCH_ITERATE(type, e, fn, args...) \ | 125 | #define XT_MATCH_ITERATE(type, e, fn, args...) \ |
| 125 | ({ \ | 126 | ({ \ |
| @@ -163,6 +164,22 @@ struct xt_counters_info { | |||
| 163 | #define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ | 164 | #define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ |
| 164 | XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) | 165 | XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) |
| 165 | 166 | ||
| 167 | #endif /* !__KERNEL__ */ | ||
| 168 | |||
| 169 | /* pos is normally a struct ipt_entry/ip6t_entry/etc. */ | ||
| 170 | #define xt_entry_foreach(pos, ehead, esize) \ | ||
| 171 | for ((pos) = (typeof(pos))(ehead); \ | ||
| 172 | (pos) < (typeof(pos))((char *)(ehead) + (esize)); \ | ||
| 173 | (pos) = (typeof(pos))((char *)(pos) + (pos)->next_offset)) | ||
| 174 | |||
| 175 | /* can only be xt_entry_match, so no use of typeof here */ | ||
| 176 | #define xt_ematch_foreach(pos, entry) \ | ||
| 177 | for ((pos) = (struct xt_entry_match *)entry->elems; \ | ||
| 178 | (pos) < (struct xt_entry_match *)((char *)(entry) + \ | ||
| 179 | (entry)->target_offset); \ | ||
| 180 | (pos) = (struct xt_entry_match *)((char *)(pos) + \ | ||
| 181 | (pos)->u.match_size)) | ||
| 182 | |||
| 166 | #ifdef __KERNEL__ | 183 | #ifdef __KERNEL__ |
| 167 | 184 | ||
| 168 | #include <linux/netdevice.h> | 185 | #include <linux/netdevice.h> |
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 0b33980611b2..e9948c0560f6 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h | |||
| @@ -211,9 +211,11 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e | |||
| 211 | return (void *)e + e->target_offset; | 211 | return (void *)e + e->target_offset; |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | #ifndef __KERNEL__ | ||
| 214 | /* fn returns 0 to continue iteration */ | 215 | /* fn returns 0 to continue iteration */ |
| 215 | #define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ | 216 | #define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ |
| 216 | XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args) | 217 | XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args) |
| 218 | #endif | ||
| 217 | 219 | ||
| 218 | /* | 220 | /* |
| 219 | * Main firewall chains definitions and global var's definitions. | 221 | * Main firewall chains definitions and global var's definitions. |
| @@ -291,14 +293,6 @@ compat_arpt_get_target(struct compat_arpt_entry *e) | |||
| 291 | 293 | ||
| 292 | #define COMPAT_ARPT_ALIGN(s) COMPAT_XT_ALIGN(s) | 294 | #define COMPAT_ARPT_ALIGN(s) COMPAT_XT_ALIGN(s) |
| 293 | 295 | ||
| 294 | /* fn returns 0 to continue iteration */ | ||
| 295 | #define COMPAT_ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ | ||
| 296 | XT_ENTRY_ITERATE(struct compat_arpt_entry, entries, size, fn, ## args) | ||
| 297 | |||
| 298 | #define COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ | ||
| 299 | XT_ENTRY_ITERATE_CONTINUE(struct compat_arpt_entry, entries, size, n, \ | ||
| 300 | fn, ## args) | ||
| 301 | |||
| 302 | #endif /* CONFIG_COMPAT */ | 296 | #endif /* CONFIG_COMPAT */ |
| 303 | #endif /*__KERNEL__*/ | 297 | #endif /*__KERNEL__*/ |
| 304 | #endif /* _ARPTABLES_H */ | 298 | #endif /* _ARPTABLES_H */ |
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 364973b42133..704a7b6e8169 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h | |||
| @@ -223,6 +223,7 @@ ipt_get_target(struct ipt_entry *e) | |||
| 223 | return (void *)e + e->target_offset; | 223 | return (void *)e + e->target_offset; |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | #ifndef __KERNEL__ | ||
| 226 | /* fn returns 0 to continue iteration */ | 227 | /* fn returns 0 to continue iteration */ |
| 227 | #define IPT_MATCH_ITERATE(e, fn, args...) \ | 228 | #define IPT_MATCH_ITERATE(e, fn, args...) \ |
| 228 | XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args) | 229 | XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args) |
| @@ -230,6 +231,7 @@ ipt_get_target(struct ipt_entry *e) | |||
| 230 | /* fn returns 0 to continue iteration */ | 231 | /* fn returns 0 to continue iteration */ |
| 231 | #define IPT_ENTRY_ITERATE(entries, size, fn, args...) \ | 232 | #define IPT_ENTRY_ITERATE(entries, size, fn, args...) \ |
| 232 | XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args) | 233 | XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args) |
| 234 | #endif | ||
| 233 | 235 | ||
| 234 | /* | 236 | /* |
| 235 | * Main firewall chains definitions and global var's definitions. | 237 | * Main firewall chains definitions and global var's definitions. |
| @@ -313,19 +315,6 @@ compat_ipt_get_target(struct compat_ipt_entry *e) | |||
| 313 | 315 | ||
| 314 | #define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s) | 316 | #define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s) |
| 315 | 317 | ||
| 316 | /* fn returns 0 to continue iteration */ | ||
| 317 | #define COMPAT_IPT_MATCH_ITERATE(e, fn, args...) \ | ||
| 318 | XT_MATCH_ITERATE(struct compat_ipt_entry, e, fn, ## args) | ||
| 319 | |||
| 320 | /* fn returns 0 to continue iteration */ | ||
| 321 | #define COMPAT_IPT_ENTRY_ITERATE(entries, size, fn, args...) \ | ||
| 322 | XT_ENTRY_ITERATE(struct compat_ipt_entry, entries, size, fn, ## args) | ||
| 323 | |||
| 324 | /* fn returns 0 to continue iteration */ | ||
| 325 | #define COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ | ||
| 326 | XT_ENTRY_ITERATE_CONTINUE(struct compat_ipt_entry, entries, size, n, \ | ||
| 327 | fn, ## args) | ||
| 328 | |||
| 329 | #endif /* CONFIG_COMPAT */ | 318 | #endif /* CONFIG_COMPAT */ |
| 330 | #endif /*__KERNEL__*/ | 319 | #endif /*__KERNEL__*/ |
| 331 | #endif /* _IPTABLES_H */ | 320 | #endif /* _IPTABLES_H */ |
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 8031eb486a10..e5ba03d783c6 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h | |||
| @@ -280,6 +280,7 @@ ip6t_get_target(struct ip6t_entry *e) | |||
| 280 | return (void *)e + e->target_offset; | 280 | return (void *)e + e->target_offset; |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | #ifndef __KERNEL__ | ||
| 283 | /* fn returns 0 to continue iteration */ | 284 | /* fn returns 0 to continue iteration */ |
| 284 | #define IP6T_MATCH_ITERATE(e, fn, args...) \ | 285 | #define IP6T_MATCH_ITERATE(e, fn, args...) \ |
| 285 | XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args) | 286 | XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args) |
| @@ -287,6 +288,7 @@ ip6t_get_target(struct ip6t_entry *e) | |||
| 287 | /* fn returns 0 to continue iteration */ | 288 | /* fn returns 0 to continue iteration */ |
| 288 | #define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ | 289 | #define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ |
| 289 | XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args) | 290 | XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args) |
| 291 | #endif | ||
| 290 | 292 | ||
| 291 | /* | 293 | /* |
| 292 | * Main firewall chains definitions and global var's definitions. | 294 | * Main firewall chains definitions and global var's definitions. |
| @@ -341,18 +343,6 @@ compat_ip6t_get_target(struct compat_ip6t_entry *e) | |||
| 341 | 343 | ||
| 342 | #define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s) | 344 | #define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s) |
| 343 | 345 | ||
| 344 | /* fn returns 0 to continue iteration */ | ||
| 345 | #define COMPAT_IP6T_MATCH_ITERATE(e, fn, args...) \ | ||
| 346 | XT_MATCH_ITERATE(struct compat_ip6t_entry, e, fn, ## args) | ||
| 347 | |||
| 348 | /* fn returns 0 to continue iteration */ | ||
| 349 | #define COMPAT_IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ | ||
| 350 | XT_ENTRY_ITERATE(struct compat_ip6t_entry, entries, size, fn, ## args) | ||
| 351 | |||
| 352 | #define COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ | ||
| 353 | XT_ENTRY_ITERATE_CONTINUE(struct compat_ip6t_entry, entries, size, n, \ | ||
| 354 | fn, ## args) | ||
| 355 | |||
| 356 | #endif /* CONFIG_COMPAT */ | 346 | #endif /* CONFIG_COMPAT */ |
| 357 | #endif /*__KERNEL__*/ | 347 | #endif /*__KERNEL__*/ |
| 358 | #endif /* _IP6_TABLES_H */ | 348 | #endif /* _IP6_TABLES_H */ |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 4db5c1ece0f9..57098dcda294 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
| @@ -512,8 +512,7 @@ static inline int check_target(struct arpt_entry *e, const char *name) | |||
| 512 | } | 512 | } |
| 513 | 513 | ||
| 514 | static inline int | 514 | static inline int |
| 515 | find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, | 515 | find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) |
| 516 | unsigned int *i) | ||
| 517 | { | 516 | { |
| 518 | struct arpt_entry_target *t; | 517 | struct arpt_entry_target *t; |
| 519 | struct xt_target *target; | 518 | struct xt_target *target; |
| @@ -538,8 +537,6 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, | |||
| 538 | ret = check_target(e, name); | 537 | ret = check_target(e, name); |
| 539 | if (ret) | 538 | if (ret) |
| 540 | goto err; | 539 | goto err; |
| 541 | |||
| 542 | (*i)++; | ||
| 543 | return 0; | 540 | return 0; |
| 544 | err: | 541 | err: |
| 545 | module_put(t->u.kernel.target->me); | 542 | module_put(t->u.kernel.target->me); |
| @@ -568,8 +565,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, | |||
| 568 | const unsigned char *limit, | 565 | const unsigned char *limit, |
| 569 | const unsigned int *hook_entries, | 566 | const unsigned int *hook_entries, |
| 570 | const unsigned int *underflows, | 567 | const unsigned int *underflows, |
| 571 | unsigned int valid_hooks, | 568 | unsigned int valid_hooks) |
| 572 | unsigned int *i) | ||
| 573 | { | 569 | { |
| 574 | unsigned int h; | 570 | unsigned int h; |
| 575 | 571 | ||
| @@ -606,19 +602,14 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, | |||
| 606 | /* Clear counters and comefrom */ | 602 | /* Clear counters and comefrom */ |
| 607 | e->counters = ((struct xt_counters) { 0, 0 }); | 603 | e->counters = ((struct xt_counters) { 0, 0 }); |
| 608 | e->comefrom = 0; | 604 | e->comefrom = 0; |
| 609 | |||
| 610 | (*i)++; | ||
| 611 | return 0; | 605 | return 0; |
| 612 | } | 606 | } |
| 613 | 607 | ||
| 614 | static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) | 608 | static inline void cleanup_entry(struct arpt_entry *e) |
| 615 | { | 609 | { |
| 616 | struct xt_tgdtor_param par; | 610 | struct xt_tgdtor_param par; |
| 617 | struct arpt_entry_target *t; | 611 | struct arpt_entry_target *t; |
| 618 | 612 | ||
| 619 | if (i && (*i)-- == 0) | ||
| 620 | return 1; | ||
| 621 | |||
| 622 | t = arpt_get_target(e); | 613 | t = arpt_get_target(e); |
| 623 | par.target = t->u.kernel.target; | 614 | par.target = t->u.kernel.target; |
| 624 | par.targinfo = t->data; | 615 | par.targinfo = t->data; |
| @@ -626,26 +617,20 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) | |||
| 626 | if (par.target->destroy != NULL) | 617 | if (par.target->destroy != NULL) |
| 627 | par.target->destroy(&par); | 618 | par.target->destroy(&par); |
| 628 | module_put(par.target->me); | 619 | module_put(par.target->me); |
| 629 | return 0; | ||
| 630 | } | 620 | } |
| 631 | 621 | ||
| 632 | /* Checks and translates the user-supplied table segment (held in | 622 | /* Checks and translates the user-supplied table segment (held in |
| 633 | * newinfo). | 623 | * newinfo). |
| 634 | */ | 624 | */ |
| 635 | static int translate_table(const char *name, | 625 | static int translate_table(struct xt_table_info *newinfo, void *entry0, |
| 636 | unsigned int valid_hooks, | 626 | const struct arpt_replace *repl) |
| 637 | struct xt_table_info *newinfo, | ||
| 638 | void *entry0, | ||
| 639 | unsigned int size, | ||
| 640 | unsigned int number, | ||
| 641 | const unsigned int *hook_entries, | ||
| 642 | const unsigned int *underflows) | ||
| 643 | { | 627 | { |
| 628 | struct arpt_entry *iter; | ||
| 644 | unsigned int i; | 629 | unsigned int i; |
| 645 | int ret; | 630 | int ret = 0; |
| 646 | 631 | ||
| 647 | newinfo->size = size; | 632 | newinfo->size = repl->size; |
| 648 | newinfo->number = number; | 633 | newinfo->number = repl->num_entries; |
| 649 | 634 | ||
| 650 | /* Init all hooks to impossible value. */ | 635 | /* Init all hooks to impossible value. */ |
| 651 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { | 636 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { |
| @@ -657,52 +642,61 @@ static int translate_table(const char *name, | |||
| 657 | i = 0; | 642 | i = 0; |
| 658 | 643 | ||
| 659 | /* Walk through entries, checking offsets. */ | 644 | /* Walk through entries, checking offsets. */ |
| 660 | ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 645 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 661 | check_entry_size_and_hooks, | 646 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
| 662 | newinfo, | 647 | entry0 + repl->size, repl->hook_entry, repl->underflow, |
| 663 | entry0, | 648 | repl->valid_hooks); |
| 664 | entry0 + size, | 649 | if (ret != 0) |
| 665 | hook_entries, underflows, valid_hooks, &i); | 650 | break; |
| 651 | ++i; | ||
| 652 | } | ||
| 666 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); | 653 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); |
| 667 | if (ret != 0) | 654 | if (ret != 0) |
| 668 | return ret; | 655 | return ret; |
| 669 | 656 | ||
| 670 | if (i != number) { | 657 | if (i != repl->num_entries) { |
| 671 | duprintf("translate_table: %u not %u entries\n", | 658 | duprintf("translate_table: %u not %u entries\n", |
| 672 | i, number); | 659 | i, repl->num_entries); |
| 673 | return -EINVAL; | 660 | return -EINVAL; |
| 674 | } | 661 | } |
| 675 | 662 | ||
| 676 | /* Check hooks all assigned */ | 663 | /* Check hooks all assigned */ |
| 677 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { | 664 | for (i = 0; i < NF_ARP_NUMHOOKS; i++) { |
| 678 | /* Only hooks which are valid */ | 665 | /* Only hooks which are valid */ |
| 679 | if (!(valid_hooks & (1 << i))) | 666 | if (!(repl->valid_hooks & (1 << i))) |
| 680 | continue; | 667 | continue; |
| 681 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 668 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
| 682 | duprintf("Invalid hook entry %u %u\n", | 669 | duprintf("Invalid hook entry %u %u\n", |
| 683 | i, hook_entries[i]); | 670 | i, repl->hook_entry[i]); |
| 684 | return -EINVAL; | 671 | return -EINVAL; |
| 685 | } | 672 | } |
| 686 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 673 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
| 687 | duprintf("Invalid underflow %u %u\n", | 674 | duprintf("Invalid underflow %u %u\n", |
| 688 | i, underflows[i]); | 675 | i, repl->underflow[i]); |
| 689 | return -EINVAL; | 676 | return -EINVAL; |
| 690 | } | 677 | } |
| 691 | } | 678 | } |
| 692 | 679 | ||
| 693 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) { | 680 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) { |
| 694 | duprintf("Looping hook\n"); | 681 | duprintf("Looping hook\n"); |
| 695 | return -ELOOP; | 682 | return -ELOOP; |
| 696 | } | 683 | } |
| 697 | 684 | ||
| 698 | /* Finally, each sanity check must pass */ | 685 | /* Finally, each sanity check must pass */ |
| 699 | i = 0; | 686 | i = 0; |
| 700 | ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 687 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 701 | find_check_entry, name, size, &i); | 688 | ret = find_check_entry(iter, repl->name, repl->size); |
| 689 | if (ret != 0) | ||
| 690 | break; | ||
| 691 | ++i; | ||
| 692 | } | ||
| 702 | 693 | ||
| 703 | if (ret != 0) { | 694 | if (ret != 0) { |
| 704 | ARPT_ENTRY_ITERATE(entry0, newinfo->size, | 695 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 705 | cleanup_entry, &i); | 696 | if (i-- == 0) |
| 697 | break; | ||
| 698 | cleanup_entry(iter); | ||
| 699 | } | ||
| 706 | return ret; | 700 | return ret; |
| 707 | } | 701 | } |
| 708 | 702 | ||
| @@ -715,30 +709,10 @@ static int translate_table(const char *name, | |||
| 715 | return ret; | 709 | return ret; |
| 716 | } | 710 | } |
| 717 | 711 | ||
| 718 | /* Gets counters. */ | ||
| 719 | static inline int add_entry_to_counter(const struct arpt_entry *e, | ||
| 720 | struct xt_counters total[], | ||
| 721 | unsigned int *i) | ||
| 722 | { | ||
| 723 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
| 724 | |||
| 725 | (*i)++; | ||
| 726 | return 0; | ||
| 727 | } | ||
| 728 | |||
| 729 | static inline int set_entry_to_counter(const struct arpt_entry *e, | ||
| 730 | struct xt_counters total[], | ||
| 731 | unsigned int *i) | ||
| 732 | { | ||
| 733 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
| 734 | |||
| 735 | (*i)++; | ||
| 736 | return 0; | ||
| 737 | } | ||
| 738 | |||
| 739 | static void get_counters(const struct xt_table_info *t, | 712 | static void get_counters(const struct xt_table_info *t, |
| 740 | struct xt_counters counters[]) | 713 | struct xt_counters counters[]) |
| 741 | { | 714 | { |
| 715 | struct arpt_entry *iter; | ||
| 742 | unsigned int cpu; | 716 | unsigned int cpu; |
| 743 | unsigned int i; | 717 | unsigned int i; |
| 744 | unsigned int curcpu; | 718 | unsigned int curcpu; |
| @@ -754,22 +728,22 @@ static void get_counters(const struct xt_table_info *t, | |||
| 754 | curcpu = smp_processor_id(); | 728 | curcpu = smp_processor_id(); |
| 755 | 729 | ||
| 756 | i = 0; | 730 | i = 0; |
| 757 | ARPT_ENTRY_ITERATE(t->entries[curcpu], | 731 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
| 758 | t->size, | 732 | SET_COUNTER(counters[i], iter->counters.bcnt, |
| 759 | set_entry_to_counter, | 733 | iter->counters.pcnt); |
| 760 | counters, | 734 | ++i; |
| 761 | &i); | 735 | } |
| 762 | 736 | ||
| 763 | for_each_possible_cpu(cpu) { | 737 | for_each_possible_cpu(cpu) { |
| 764 | if (cpu == curcpu) | 738 | if (cpu == curcpu) |
| 765 | continue; | 739 | continue; |
| 766 | i = 0; | 740 | i = 0; |
| 767 | xt_info_wrlock(cpu); | 741 | xt_info_wrlock(cpu); |
| 768 | ARPT_ENTRY_ITERATE(t->entries[cpu], | 742 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
| 769 | t->size, | 743 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
| 770 | add_entry_to_counter, | 744 | iter->counters.pcnt); |
| 771 | counters, | 745 | ++i; |
| 772 | &i); | 746 | } |
| 773 | xt_info_wrunlock(cpu); | 747 | xt_info_wrunlock(cpu); |
| 774 | } | 748 | } |
| 775 | local_bh_enable(); | 749 | local_bh_enable(); |
| @@ -899,7 +873,9 @@ static int compat_calc_entry(const struct arpt_entry *e, | |||
| 899 | static int compat_table_info(const struct xt_table_info *info, | 873 | static int compat_table_info(const struct xt_table_info *info, |
| 900 | struct xt_table_info *newinfo) | 874 | struct xt_table_info *newinfo) |
| 901 | { | 875 | { |
| 876 | struct arpt_entry *iter; | ||
| 902 | void *loc_cpu_entry; | 877 | void *loc_cpu_entry; |
| 878 | int ret; | ||
| 903 | 879 | ||
| 904 | if (!newinfo || !info) | 880 | if (!newinfo || !info) |
| 905 | return -EINVAL; | 881 | return -EINVAL; |
| @@ -908,9 +884,12 @@ static int compat_table_info(const struct xt_table_info *info, | |||
| 908 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 884 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
| 909 | newinfo->initial_entries = 0; | 885 | newinfo->initial_entries = 0; |
| 910 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 886 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
| 911 | return ARPT_ENTRY_ITERATE(loc_cpu_entry, info->size, | 887 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
| 912 | compat_calc_entry, info, loc_cpu_entry, | 888 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
| 913 | newinfo); | 889 | if (ret != 0) |
| 890 | return ret; | ||
| 891 | } | ||
| 892 | return 0; | ||
| 914 | } | 893 | } |
| 915 | #endif | 894 | #endif |
| 916 | 895 | ||
| @@ -1025,6 +1004,7 @@ static int __do_replace(struct net *net, const char *name, | |||
| 1025 | struct xt_table_info *oldinfo; | 1004 | struct xt_table_info *oldinfo; |
| 1026 | struct xt_counters *counters; | 1005 | struct xt_counters *counters; |
| 1027 | void *loc_cpu_old_entry; | 1006 | void *loc_cpu_old_entry; |
| 1007 | struct arpt_entry *iter; | ||
| 1028 | 1008 | ||
| 1029 | ret = 0; | 1009 | ret = 0; |
| 1030 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), | 1010 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), |
| @@ -1068,8 +1048,8 @@ static int __do_replace(struct net *net, const char *name, | |||
| 1068 | 1048 | ||
| 1069 | /* Decrease module usage counts and free resource */ | 1049 | /* Decrease module usage counts and free resource */ |
| 1070 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1050 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
| 1071 | ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1051 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
| 1072 | NULL); | 1052 | cleanup_entry(iter); |
| 1073 | 1053 | ||
| 1074 | xt_free_table_info(oldinfo); | 1054 | xt_free_table_info(oldinfo); |
| 1075 | if (copy_to_user(counters_ptr, counters, | 1055 | if (copy_to_user(counters_ptr, counters, |
| @@ -1095,6 +1075,7 @@ static int do_replace(struct net *net, const void __user *user, | |||
| 1095 | struct arpt_replace tmp; | 1075 | struct arpt_replace tmp; |
| 1096 | struct xt_table_info *newinfo; | 1076 | struct xt_table_info *newinfo; |
| 1097 | void *loc_cpu_entry; | 1077 | void *loc_cpu_entry; |
| 1078 | struct arpt_entry *iter; | ||
| 1098 | 1079 | ||
| 1099 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1080 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
| 1100 | return -EFAULT; | 1081 | return -EFAULT; |
| @@ -1115,9 +1096,7 @@ static int do_replace(struct net *net, const void __user *user, | |||
| 1115 | goto free_newinfo; | 1096 | goto free_newinfo; |
| 1116 | } | 1097 | } |
| 1117 | 1098 | ||
| 1118 | ret = translate_table(tmp.name, tmp.valid_hooks, | 1099 | ret = translate_table(newinfo, loc_cpu_entry, &tmp); |
| 1119 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
| 1120 | tmp.hook_entry, tmp.underflow); | ||
| 1121 | if (ret != 0) | 1100 | if (ret != 0) |
| 1122 | goto free_newinfo; | 1101 | goto free_newinfo; |
| 1123 | 1102 | ||
| @@ -1130,25 +1109,13 @@ static int do_replace(struct net *net, const void __user *user, | |||
| 1130 | return 0; | 1109 | return 0; |
| 1131 | 1110 | ||
| 1132 | free_newinfo_untrans: | 1111 | free_newinfo_untrans: |
| 1133 | ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1112 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
| 1113 | cleanup_entry(iter); | ||
| 1134 | free_newinfo: | 1114 | free_newinfo: |
| 1135 | xt_free_table_info(newinfo); | 1115 | xt_free_table_info(newinfo); |
| 1136 | return ret; | 1116 | return ret; |
| 1137 | } | 1117 | } |
| 1138 | 1118 | ||
| 1139 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 1140 | * and everything is OK. */ | ||
| 1141 | static int | ||
| 1142 | add_counter_to_entry(struct arpt_entry *e, | ||
| 1143 | const struct xt_counters addme[], | ||
| 1144 | unsigned int *i) | ||
| 1145 | { | ||
| 1146 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 1147 | |||
| 1148 | (*i)++; | ||
| 1149 | return 0; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | static int do_add_counters(struct net *net, const void __user *user, | 1119 | static int do_add_counters(struct net *net, const void __user *user, |
| 1153 | unsigned int len, int compat) | 1120 | unsigned int len, int compat) |
| 1154 | { | 1121 | { |
| @@ -1163,6 +1130,7 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
| 1163 | const struct xt_table_info *private; | 1130 | const struct xt_table_info *private; |
| 1164 | int ret = 0; | 1131 | int ret = 0; |
| 1165 | void *loc_cpu_entry; | 1132 | void *loc_cpu_entry; |
| 1133 | struct arpt_entry *iter; | ||
| 1166 | #ifdef CONFIG_COMPAT | 1134 | #ifdef CONFIG_COMPAT |
| 1167 | struct compat_xt_counters_info compat_tmp; | 1135 | struct compat_xt_counters_info compat_tmp; |
| 1168 | 1136 | ||
| @@ -1220,11 +1188,10 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
| 1220 | curcpu = smp_processor_id(); | 1188 | curcpu = smp_processor_id(); |
| 1221 | loc_cpu_entry = private->entries[curcpu]; | 1189 | loc_cpu_entry = private->entries[curcpu]; |
| 1222 | xt_info_wrlock(curcpu); | 1190 | xt_info_wrlock(curcpu); |
| 1223 | ARPT_ENTRY_ITERATE(loc_cpu_entry, | 1191 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
| 1224 | private->size, | 1192 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
| 1225 | add_counter_to_entry, | 1193 | ++i; |
| 1226 | paddc, | 1194 | } |
| 1227 | &i); | ||
| 1228 | xt_info_wrunlock(curcpu); | 1195 | xt_info_wrunlock(curcpu); |
| 1229 | unlock_up_free: | 1196 | unlock_up_free: |
| 1230 | local_bh_enable(); | 1197 | local_bh_enable(); |
| @@ -1237,17 +1204,12 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
| 1237 | } | 1204 | } |
| 1238 | 1205 | ||
| 1239 | #ifdef CONFIG_COMPAT | 1206 | #ifdef CONFIG_COMPAT |
| 1240 | static inline int | 1207 | static inline void compat_release_entry(struct compat_arpt_entry *e) |
| 1241 | compat_release_entry(struct compat_arpt_entry *e, unsigned int *i) | ||
| 1242 | { | 1208 | { |
| 1243 | struct arpt_entry_target *t; | 1209 | struct arpt_entry_target *t; |
| 1244 | 1210 | ||
| 1245 | if (i && (*i)-- == 0) | ||
| 1246 | return 1; | ||
| 1247 | |||
| 1248 | t = compat_arpt_get_target(e); | 1211 | t = compat_arpt_get_target(e); |
| 1249 | module_put(t->u.kernel.target->me); | 1212 | module_put(t->u.kernel.target->me); |
| 1250 | return 0; | ||
| 1251 | } | 1213 | } |
| 1252 | 1214 | ||
| 1253 | static inline int | 1215 | static inline int |
| @@ -1258,7 +1220,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, | |||
| 1258 | const unsigned char *limit, | 1220 | const unsigned char *limit, |
| 1259 | const unsigned int *hook_entries, | 1221 | const unsigned int *hook_entries, |
| 1260 | const unsigned int *underflows, | 1222 | const unsigned int *underflows, |
| 1261 | unsigned int *i, | ||
| 1262 | const char *name) | 1223 | const char *name) |
| 1263 | { | 1224 | { |
| 1264 | struct arpt_entry_target *t; | 1225 | struct arpt_entry_target *t; |
| @@ -1318,8 +1279,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, | |||
| 1318 | /* Clear counters and comefrom */ | 1279 | /* Clear counters and comefrom */ |
| 1319 | memset(&e->counters, 0, sizeof(e->counters)); | 1280 | memset(&e->counters, 0, sizeof(e->counters)); |
| 1320 | e->comefrom = 0; | 1281 | e->comefrom = 0; |
| 1321 | |||
| 1322 | (*i)++; | ||
| 1323 | return 0; | 1282 | return 0; |
| 1324 | 1283 | ||
| 1325 | release_target: | 1284 | release_target: |
| @@ -1363,19 +1322,6 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, | |||
| 1363 | return ret; | 1322 | return ret; |
| 1364 | } | 1323 | } |
| 1365 | 1324 | ||
| 1366 | static inline int compat_check_entry(struct arpt_entry *e, const char *name, | ||
| 1367 | unsigned int *i) | ||
| 1368 | { | ||
| 1369 | int ret; | ||
| 1370 | |||
| 1371 | ret = check_target(e, name); | ||
| 1372 | if (ret) | ||
| 1373 | return ret; | ||
| 1374 | |||
| 1375 | (*i)++; | ||
| 1376 | return 0; | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | static int translate_compat_table(const char *name, | 1325 | static int translate_compat_table(const char *name, |
| 1380 | unsigned int valid_hooks, | 1326 | unsigned int valid_hooks, |
| 1381 | struct xt_table_info **pinfo, | 1327 | struct xt_table_info **pinfo, |
| @@ -1388,8 +1334,10 @@ static int translate_compat_table(const char *name, | |||
| 1388 | unsigned int i, j; | 1334 | unsigned int i, j; |
| 1389 | struct xt_table_info *newinfo, *info; | 1335 | struct xt_table_info *newinfo, *info; |
| 1390 | void *pos, *entry0, *entry1; | 1336 | void *pos, *entry0, *entry1; |
| 1337 | struct compat_arpt_entry *iter0; | ||
| 1338 | struct arpt_entry *iter1; | ||
| 1391 | unsigned int size; | 1339 | unsigned int size; |
| 1392 | int ret; | 1340 | int ret = 0; |
| 1393 | 1341 | ||
| 1394 | info = *pinfo; | 1342 | info = *pinfo; |
| 1395 | entry0 = *pentry0; | 1343 | entry0 = *pentry0; |
| @@ -1406,13 +1354,14 @@ static int translate_compat_table(const char *name, | |||
| 1406 | j = 0; | 1354 | j = 0; |
| 1407 | xt_compat_lock(NFPROTO_ARP); | 1355 | xt_compat_lock(NFPROTO_ARP); |
| 1408 | /* Walk through entries, checking offsets. */ | 1356 | /* Walk through entries, checking offsets. */ |
| 1409 | ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, | 1357 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1410 | check_compat_entry_size_and_hooks, | 1358 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
| 1411 | info, &size, entry0, | 1359 | entry0, entry0 + total_size, hook_entries, underflows, |
| 1412 | entry0 + total_size, | 1360 | name); |
| 1413 | hook_entries, underflows, &j, name); | 1361 | if (ret != 0) |
| 1414 | if (ret != 0) | 1362 | goto out_unlock; |
| 1415 | goto out_unlock; | 1363 | ++j; |
| 1364 | } | ||
| 1416 | 1365 | ||
| 1417 | ret = -EINVAL; | 1366 | ret = -EINVAL; |
| 1418 | if (j != number) { | 1367 | if (j != number) { |
| @@ -1451,9 +1400,12 @@ static int translate_compat_table(const char *name, | |||
| 1451 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1400 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
| 1452 | pos = entry1; | 1401 | pos = entry1; |
| 1453 | size = total_size; | 1402 | size = total_size; |
| 1454 | ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, | 1403 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1455 | compat_copy_entry_from_user, | 1404 | ret = compat_copy_entry_from_user(iter0, &pos, |
| 1456 | &pos, &size, name, newinfo, entry1); | 1405 | &size, name, newinfo, entry1); |
| 1406 | if (ret != 0) | ||
| 1407 | break; | ||
| 1408 | } | ||
| 1457 | xt_compat_flush_offsets(NFPROTO_ARP); | 1409 | xt_compat_flush_offsets(NFPROTO_ARP); |
| 1458 | xt_compat_unlock(NFPROTO_ARP); | 1410 | xt_compat_unlock(NFPROTO_ARP); |
| 1459 | if (ret) | 1411 | if (ret) |
| @@ -1464,13 +1416,32 @@ static int translate_compat_table(const char *name, | |||
| 1464 | goto free_newinfo; | 1416 | goto free_newinfo; |
| 1465 | 1417 | ||
| 1466 | i = 0; | 1418 | i = 0; |
| 1467 | ret = ARPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1419 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
| 1468 | name, &i); | 1420 | ret = check_target(iter1, name); |
| 1421 | if (ret != 0) | ||
| 1422 | break; | ||
| 1423 | ++i; | ||
| 1424 | } | ||
| 1469 | if (ret) { | 1425 | if (ret) { |
| 1426 | /* | ||
| 1427 | * The first i matches need cleanup_entry (calls ->destroy) | ||
| 1428 | * because they had called ->check already. The other j-i | ||
| 1429 | * entries need only release. | ||
| 1430 | */ | ||
| 1431 | int skip = i; | ||
| 1470 | j -= i; | 1432 | j -= i; |
| 1471 | COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1433 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
| 1472 | compat_release_entry, &j); | 1434 | if (skip-- > 0) |
| 1473 | ARPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i); | 1435 | continue; |
| 1436 | if (j-- == 0) | ||
| 1437 | break; | ||
| 1438 | compat_release_entry(iter0); | ||
| 1439 | } | ||
| 1440 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
| 1441 | if (i-- == 0) | ||
| 1442 | break; | ||
| 1443 | cleanup_entry(iter1); | ||
| 1444 | } | ||
| 1474 | xt_free_table_info(newinfo); | 1445 | xt_free_table_info(newinfo); |
| 1475 | return ret; | 1446 | return ret; |
| 1476 | } | 1447 | } |
| @@ -1488,7 +1459,11 @@ static int translate_compat_table(const char *name, | |||
| 1488 | free_newinfo: | 1459 | free_newinfo: |
| 1489 | xt_free_table_info(newinfo); | 1460 | xt_free_table_info(newinfo); |
| 1490 | out: | 1461 | out: |
| 1491 | COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1462 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1463 | if (j-- == 0) | ||
| 1464 | break; | ||
| 1465 | compat_release_entry(iter0); | ||
| 1466 | } | ||
| 1492 | return ret; | 1467 | return ret; |
| 1493 | out_unlock: | 1468 | out_unlock: |
| 1494 | xt_compat_flush_offsets(NFPROTO_ARP); | 1469 | xt_compat_flush_offsets(NFPROTO_ARP); |
| @@ -1515,6 +1490,7 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
| 1515 | struct compat_arpt_replace tmp; | 1490 | struct compat_arpt_replace tmp; |
| 1516 | struct xt_table_info *newinfo; | 1491 | struct xt_table_info *newinfo; |
| 1517 | void *loc_cpu_entry; | 1492 | void *loc_cpu_entry; |
| 1493 | struct arpt_entry *iter; | ||
| 1518 | 1494 | ||
| 1519 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1495 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
| 1520 | return -EFAULT; | 1496 | return -EFAULT; |
| @@ -1552,7 +1528,8 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
| 1552 | return 0; | 1528 | return 0; |
| 1553 | 1529 | ||
| 1554 | free_newinfo_untrans: | 1530 | free_newinfo_untrans: |
| 1555 | ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1531 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
| 1532 | cleanup_entry(iter); | ||
| 1556 | free_newinfo: | 1533 | free_newinfo: |
| 1557 | xt_free_table_info(newinfo); | 1534 | xt_free_table_info(newinfo); |
| 1558 | return ret; | 1535 | return ret; |
| @@ -1586,7 +1563,7 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, | |||
| 1586 | static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | 1563 | static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, |
| 1587 | compat_uint_t *size, | 1564 | compat_uint_t *size, |
| 1588 | struct xt_counters *counters, | 1565 | struct xt_counters *counters, |
| 1589 | unsigned int *i) | 1566 | unsigned int i) |
| 1590 | { | 1567 | { |
| 1591 | struct arpt_entry_target *t; | 1568 | struct arpt_entry_target *t; |
| 1592 | struct compat_arpt_entry __user *ce; | 1569 | struct compat_arpt_entry __user *ce; |
| @@ -1594,14 +1571,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | |||
| 1594 | compat_uint_t origsize; | 1571 | compat_uint_t origsize; |
| 1595 | int ret; | 1572 | int ret; |
| 1596 | 1573 | ||
| 1597 | ret = -EFAULT; | ||
| 1598 | origsize = *size; | 1574 | origsize = *size; |
| 1599 | ce = (struct compat_arpt_entry __user *)*dstptr; | 1575 | ce = (struct compat_arpt_entry __user *)*dstptr; |
| 1600 | if (copy_to_user(ce, e, sizeof(struct arpt_entry))) | 1576 | if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || |
| 1601 | goto out; | 1577 | copy_to_user(&ce->counters, &counters[i], |
| 1602 | 1578 | sizeof(counters[i])) != 0) | |
| 1603 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1579 | return -EFAULT; |
| 1604 | goto out; | ||
| 1605 | 1580 | ||
| 1606 | *dstptr += sizeof(struct compat_arpt_entry); | 1581 | *dstptr += sizeof(struct compat_arpt_entry); |
| 1607 | *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); | 1582 | *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); |
| @@ -1611,18 +1586,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | |||
| 1611 | t = arpt_get_target(e); | 1586 | t = arpt_get_target(e); |
| 1612 | ret = xt_compat_target_to_user(t, dstptr, size); | 1587 | ret = xt_compat_target_to_user(t, dstptr, size); |
| 1613 | if (ret) | 1588 | if (ret) |
| 1614 | goto out; | 1589 | return ret; |
| 1615 | ret = -EFAULT; | ||
| 1616 | next_offset = e->next_offset - (origsize - *size); | 1590 | next_offset = e->next_offset - (origsize - *size); |
| 1617 | if (put_user(target_offset, &ce->target_offset)) | 1591 | if (put_user(target_offset, &ce->target_offset) != 0 || |
| 1618 | goto out; | 1592 | put_user(next_offset, &ce->next_offset) != 0) |
| 1619 | if (put_user(next_offset, &ce->next_offset)) | 1593 | return -EFAULT; |
| 1620 | goto out; | ||
| 1621 | |||
| 1622 | (*i)++; | ||
| 1623 | return 0; | 1594 | return 0; |
| 1624 | out: | ||
| 1625 | return ret; | ||
| 1626 | } | 1595 | } |
| 1627 | 1596 | ||
| 1628 | static int compat_copy_entries_to_user(unsigned int total_size, | 1597 | static int compat_copy_entries_to_user(unsigned int total_size, |
| @@ -1636,6 +1605,7 @@ static int compat_copy_entries_to_user(unsigned int total_size, | |||
| 1636 | int ret = 0; | 1605 | int ret = 0; |
| 1637 | void *loc_cpu_entry; | 1606 | void *loc_cpu_entry; |
| 1638 | unsigned int i = 0; | 1607 | unsigned int i = 0; |
| 1608 | struct arpt_entry *iter; | ||
| 1639 | 1609 | ||
| 1640 | counters = alloc_counters(table); | 1610 | counters = alloc_counters(table); |
| 1641 | if (IS_ERR(counters)) | 1611 | if (IS_ERR(counters)) |
| @@ -1645,9 +1615,12 @@ static int compat_copy_entries_to_user(unsigned int total_size, | |||
| 1645 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1615 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| 1646 | pos = userptr; | 1616 | pos = userptr; |
| 1647 | size = total_size; | 1617 | size = total_size; |
| 1648 | ret = ARPT_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1618 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
| 1649 | compat_copy_entry_to_user, | 1619 | ret = compat_copy_entry_to_user(iter, &pos, |
| 1650 | &pos, &size, counters, &i); | 1620 | &size, counters, i++); |
| 1621 | if (ret != 0) | ||
| 1622 | break; | ||
| 1623 | } | ||
| 1651 | vfree(counters); | 1624 | vfree(counters); |
| 1652 | return ret; | 1625 | return ret; |
| 1653 | } | 1626 | } |
| @@ -1815,12 +1788,7 @@ struct xt_table *arpt_register_table(struct net *net, | |||
| 1815 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 1788 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
| 1816 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 1789 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
| 1817 | 1790 | ||
| 1818 | ret = translate_table(table->name, table->valid_hooks, | 1791 | ret = translate_table(newinfo, loc_cpu_entry, repl); |
| 1819 | newinfo, loc_cpu_entry, repl->size, | ||
| 1820 | repl->num_entries, | ||
| 1821 | repl->hook_entry, | ||
| 1822 | repl->underflow); | ||
| 1823 | |||
| 1824 | duprintf("arpt_register_table: translate table gives %d\n", ret); | 1792 | duprintf("arpt_register_table: translate table gives %d\n", ret); |
| 1825 | if (ret != 0) | 1793 | if (ret != 0) |
| 1826 | goto out_free; | 1794 | goto out_free; |
| @@ -1843,13 +1811,14 @@ void arpt_unregister_table(struct xt_table *table) | |||
| 1843 | struct xt_table_info *private; | 1811 | struct xt_table_info *private; |
| 1844 | void *loc_cpu_entry; | 1812 | void *loc_cpu_entry; |
| 1845 | struct module *table_owner = table->me; | 1813 | struct module *table_owner = table->me; |
| 1814 | struct arpt_entry *iter; | ||
| 1846 | 1815 | ||
| 1847 | private = xt_unregister_table(table); | 1816 | private = xt_unregister_table(table); |
| 1848 | 1817 | ||
| 1849 | /* Decrease module usage counts and free resources */ | 1818 | /* Decrease module usage counts and free resources */ |
| 1850 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1819 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| 1851 | ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size, | 1820 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
| 1852 | cleanup_entry, NULL); | 1821 | cleanup_entry(iter); |
| 1853 | if (private->number > private->initial_entries) | 1822 | if (private->number > private->initial_entries) |
| 1854 | module_put(table_owner); | 1823 | module_put(table_owner); |
| 1855 | xt_free_table_info(private); | 1824 | xt_free_table_info(private); |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index e94c18bdfc68..c92f4e541cf6 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
| @@ -288,6 +288,7 @@ static void trace_packet(const struct sk_buff *skb, | |||
| 288 | const void *table_base; | 288 | const void *table_base; |
| 289 | const struct ipt_entry *root; | 289 | const struct ipt_entry *root; |
| 290 | const char *hookname, *chainname, *comment; | 290 | const char *hookname, *chainname, *comment; |
| 291 | const struct ipt_entry *iter; | ||
| 291 | unsigned int rulenum = 0; | 292 | unsigned int rulenum = 0; |
| 292 | 293 | ||
| 293 | table_base = private->entries[smp_processor_id()]; | 294 | table_base = private->entries[smp_processor_id()]; |
| @@ -296,10 +297,10 @@ static void trace_packet(const struct sk_buff *skb, | |||
| 296 | hookname = chainname = hooknames[hook]; | 297 | hookname = chainname = hooknames[hook]; |
| 297 | comment = comments[NF_IP_TRACE_COMMENT_RULE]; | 298 | comment = comments[NF_IP_TRACE_COMMENT_RULE]; |
| 298 | 299 | ||
| 299 | IPT_ENTRY_ITERATE(root, | 300 | xt_entry_foreach(iter, root, private->size - private->hook_entry[hook]) |
| 300 | private->size - private->hook_entry[hook], | 301 | if (get_chainname_rulenum(iter, e, hookname, |
| 301 | get_chainname_rulenum, | 302 | &chainname, &comment, &rulenum) != 0) |
| 302 | e, hookname, &chainname, &comment, &rulenum); | 303 | break; |
| 303 | 304 | ||
| 304 | nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo, | 305 | nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo, |
| 305 | "TRACE: %s:%s:%s:%u ", | 306 | "TRACE: %s:%s:%s:%u ", |
| @@ -365,16 +366,21 @@ ipt_do_table(struct sk_buff *skb, | |||
| 365 | 366 | ||
| 366 | do { | 367 | do { |
| 367 | const struct ipt_entry_target *t; | 368 | const struct ipt_entry_target *t; |
| 369 | const struct xt_entry_match *ematch; | ||
| 368 | 370 | ||
| 369 | IP_NF_ASSERT(e); | 371 | IP_NF_ASSERT(e); |
| 370 | IP_NF_ASSERT(back); | 372 | IP_NF_ASSERT(back); |
| 371 | if (!ip_packet_match(ip, indev, outdev, | 373 | if (!ip_packet_match(ip, indev, outdev, |
| 372 | &e->ip, mtpar.fragoff) || | 374 | &e->ip, mtpar.fragoff)) { |
| 373 | IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { | 375 | no_match: |
| 374 | e = ipt_next_entry(e); | 376 | e = ipt_next_entry(e); |
| 375 | continue; | 377 | continue; |
| 376 | } | 378 | } |
| 377 | 379 | ||
| 380 | xt_ematch_foreach(ematch, e) | ||
| 381 | if (do_match(ematch, skb, &mtpar) != 0) | ||
| 382 | goto no_match; | ||
| 383 | |||
| 378 | ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); | 384 | ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); |
| 379 | 385 | ||
| 380 | t = ipt_get_target(e); | 386 | t = ipt_get_target(e); |
| @@ -566,14 +572,10 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
| 566 | return 1; | 572 | return 1; |
| 567 | } | 573 | } |
| 568 | 574 | ||
| 569 | static int | 575 | static void cleanup_match(struct ipt_entry_match *m, struct net *net) |
| 570 | cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i) | ||
| 571 | { | 576 | { |
| 572 | struct xt_mtdtor_param par; | 577 | struct xt_mtdtor_param par; |
| 573 | 578 | ||
| 574 | if (i && (*i)-- == 0) | ||
| 575 | return 1; | ||
| 576 | |||
| 577 | par.net = net; | 579 | par.net = net; |
| 578 | par.match = m->u.kernel.match; | 580 | par.match = m->u.kernel.match; |
| 579 | par.matchinfo = m->data; | 581 | par.matchinfo = m->data; |
| @@ -581,7 +583,6 @@ cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i) | |||
| 581 | if (par.match->destroy != NULL) | 583 | if (par.match->destroy != NULL) |
| 582 | par.match->destroy(&par); | 584 | par.match->destroy(&par); |
| 583 | module_put(par.match->me); | 585 | module_put(par.match->me); |
| 584 | return 0; | ||
| 585 | } | 586 | } |
| 586 | 587 | ||
| 587 | static int | 588 | static int |
| @@ -606,8 +607,7 @@ check_entry(const struct ipt_entry *e, const char *name) | |||
| 606 | } | 607 | } |
| 607 | 608 | ||
| 608 | static int | 609 | static int |
| 609 | check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | 610 | check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par) |
| 610 | unsigned int *i) | ||
| 611 | { | 611 | { |
| 612 | const struct ipt_ip *ip = par->entryinfo; | 612 | const struct ipt_ip *ip = par->entryinfo; |
| 613 | int ret; | 613 | int ret; |
| @@ -622,13 +622,11 @@ check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | |||
| 622 | par.match->name); | 622 | par.match->name); |
| 623 | return ret; | 623 | return ret; |
| 624 | } | 624 | } |
| 625 | ++*i; | ||
| 626 | return 0; | 625 | return 0; |
| 627 | } | 626 | } |
| 628 | 627 | ||
| 629 | static int | 628 | static int |
| 630 | find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | 629 | find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par) |
| 631 | unsigned int *i) | ||
| 632 | { | 630 | { |
| 633 | struct xt_match *match; | 631 | struct xt_match *match; |
| 634 | int ret; | 632 | int ret; |
| @@ -642,7 +640,7 @@ find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par, | |||
| 642 | } | 640 | } |
| 643 | m->u.kernel.match = match; | 641 | m->u.kernel.match = match; |
| 644 | 642 | ||
| 645 | ret = check_match(m, par, i); | 643 | ret = check_match(m, par); |
| 646 | if (ret) | 644 | if (ret) |
| 647 | goto err; | 645 | goto err; |
| 648 | 646 | ||
| @@ -678,13 +676,14 @@ static int check_target(struct ipt_entry *e, struct net *net, const char *name) | |||
| 678 | 676 | ||
| 679 | static int | 677 | static int |
| 680 | find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | 678 | find_check_entry(struct ipt_entry *e, struct net *net, const char *name, |
| 681 | unsigned int size, unsigned int *i) | 679 | unsigned int size) |
| 682 | { | 680 | { |
| 683 | struct ipt_entry_target *t; | 681 | struct ipt_entry_target *t; |
| 684 | struct xt_target *target; | 682 | struct xt_target *target; |
| 685 | int ret; | 683 | int ret; |
| 686 | unsigned int j; | 684 | unsigned int j; |
| 687 | struct xt_mtchk_param mtpar; | 685 | struct xt_mtchk_param mtpar; |
| 686 | struct xt_entry_match *ematch; | ||
| 688 | 687 | ||
| 689 | ret = check_entry(e, name); | 688 | ret = check_entry(e, name); |
| 690 | if (ret) | 689 | if (ret) |
| @@ -696,9 +695,12 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
| 696 | mtpar.entryinfo = &e->ip; | 695 | mtpar.entryinfo = &e->ip; |
| 697 | mtpar.hook_mask = e->comefrom; | 696 | mtpar.hook_mask = e->comefrom; |
| 698 | mtpar.family = NFPROTO_IPV4; | 697 | mtpar.family = NFPROTO_IPV4; |
| 699 | ret = IPT_MATCH_ITERATE(e, find_check_match, &mtpar, &j); | 698 | xt_ematch_foreach(ematch, e) { |
| 700 | if (ret != 0) | 699 | ret = find_check_match(ematch, &mtpar); |
| 701 | goto cleanup_matches; | 700 | if (ret != 0) |
| 701 | goto cleanup_matches; | ||
| 702 | ++j; | ||
| 703 | } | ||
| 702 | 704 | ||
| 703 | t = ipt_get_target(e); | 705 | t = ipt_get_target(e); |
| 704 | target = try_then_request_module(xt_find_target(AF_INET, | 706 | target = try_then_request_module(xt_find_target(AF_INET, |
| @@ -715,13 +717,15 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
| 715 | ret = check_target(e, net, name); | 717 | ret = check_target(e, net, name); |
| 716 | if (ret) | 718 | if (ret) |
| 717 | goto err; | 719 | goto err; |
| 718 | |||
| 719 | (*i)++; | ||
| 720 | return 0; | 720 | return 0; |
| 721 | err: | 721 | err: |
| 722 | module_put(t->u.kernel.target->me); | 722 | module_put(t->u.kernel.target->me); |
| 723 | cleanup_matches: | 723 | cleanup_matches: |
| 724 | IPT_MATCH_ITERATE(e, cleanup_match, net, &j); | 724 | xt_ematch_foreach(ematch, e) { |
| 725 | if (j-- == 0) | ||
| 726 | break; | ||
| 727 | cleanup_match(ematch, net); | ||
| 728 | } | ||
| 725 | return ret; | 729 | return ret; |
| 726 | } | 730 | } |
| 727 | 731 | ||
| @@ -747,8 +751,7 @@ check_entry_size_and_hooks(struct ipt_entry *e, | |||
| 747 | const unsigned char *limit, | 751 | const unsigned char *limit, |
| 748 | const unsigned int *hook_entries, | 752 | const unsigned int *hook_entries, |
| 749 | const unsigned int *underflows, | 753 | const unsigned int *underflows, |
| 750 | unsigned int valid_hooks, | 754 | unsigned int valid_hooks) |
| 751 | unsigned int *i) | ||
| 752 | { | 755 | { |
| 753 | unsigned int h; | 756 | unsigned int h; |
| 754 | 757 | ||
| @@ -785,22 +788,19 @@ check_entry_size_and_hooks(struct ipt_entry *e, | |||
| 785 | /* Clear counters and comefrom */ | 788 | /* Clear counters and comefrom */ |
| 786 | e->counters = ((struct xt_counters) { 0, 0 }); | 789 | e->counters = ((struct xt_counters) { 0, 0 }); |
| 787 | e->comefrom = 0; | 790 | e->comefrom = 0; |
| 788 | |||
| 789 | (*i)++; | ||
| 790 | return 0; | 791 | return 0; |
| 791 | } | 792 | } |
| 792 | 793 | ||
| 793 | static int | 794 | static void |
| 794 | cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) | 795 | cleanup_entry(struct ipt_entry *e, struct net *net) |
| 795 | { | 796 | { |
| 796 | struct xt_tgdtor_param par; | 797 | struct xt_tgdtor_param par; |
| 797 | struct ipt_entry_target *t; | 798 | struct ipt_entry_target *t; |
| 798 | 799 | struct xt_entry_match *ematch; | |
| 799 | if (i && (*i)-- == 0) | ||
| 800 | return 1; | ||
| 801 | 800 | ||
| 802 | /* Cleanup all matches */ | 801 | /* Cleanup all matches */ |
| 803 | IPT_MATCH_ITERATE(e, cleanup_match, net, NULL); | 802 | xt_ematch_foreach(ematch, e) |
| 803 | cleanup_match(ematch, net); | ||
| 804 | t = ipt_get_target(e); | 804 | t = ipt_get_target(e); |
| 805 | 805 | ||
| 806 | par.net = net; | 806 | par.net = net; |
| @@ -810,27 +810,20 @@ cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) | |||
| 810 | if (par.target->destroy != NULL) | 810 | if (par.target->destroy != NULL) |
| 811 | par.target->destroy(&par); | 811 | par.target->destroy(&par); |
| 812 | module_put(par.target->me); | 812 | module_put(par.target->me); |
| 813 | return 0; | ||
| 814 | } | 813 | } |
| 815 | 814 | ||
| 816 | /* Checks and translates the user-supplied table segment (held in | 815 | /* Checks and translates the user-supplied table segment (held in |
| 817 | newinfo) */ | 816 | newinfo) */ |
| 818 | static int | 817 | static int |
| 819 | translate_table(struct net *net, | 818 | translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, |
| 820 | const char *name, | 819 | const struct ipt_replace *repl) |
| 821 | unsigned int valid_hooks, | ||
| 822 | struct xt_table_info *newinfo, | ||
| 823 | void *entry0, | ||
| 824 | unsigned int size, | ||
| 825 | unsigned int number, | ||
| 826 | const unsigned int *hook_entries, | ||
| 827 | const unsigned int *underflows) | ||
| 828 | { | 820 | { |
| 821 | struct ipt_entry *iter; | ||
| 829 | unsigned int i; | 822 | unsigned int i; |
| 830 | int ret; | 823 | int ret = 0; |
| 831 | 824 | ||
| 832 | newinfo->size = size; | 825 | newinfo->size = repl->size; |
| 833 | newinfo->number = number; | 826 | newinfo->number = repl->num_entries; |
| 834 | 827 | ||
| 835 | /* Init all hooks to impossible value. */ | 828 | /* Init all hooks to impossible value. */ |
| 836 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 829 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
| @@ -841,49 +834,56 @@ translate_table(struct net *net, | |||
| 841 | duprintf("translate_table: size %u\n", newinfo->size); | 834 | duprintf("translate_table: size %u\n", newinfo->size); |
| 842 | i = 0; | 835 | i = 0; |
| 843 | /* Walk through entries, checking offsets. */ | 836 | /* Walk through entries, checking offsets. */ |
| 844 | ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, | 837 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 845 | check_entry_size_and_hooks, | 838 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
| 846 | newinfo, | 839 | entry0 + repl->size, repl->hook_entry, repl->underflow, |
| 847 | entry0, | 840 | repl->valid_hooks); |
| 848 | entry0 + size, | 841 | if (ret != 0) |
| 849 | hook_entries, underflows, valid_hooks, &i); | 842 | return ret; |
| 850 | if (ret != 0) | 843 | ++i; |
| 851 | return ret; | 844 | } |
| 852 | 845 | ||
| 853 | if (i != number) { | 846 | if (i != repl->num_entries) { |
| 854 | duprintf("translate_table: %u not %u entries\n", | 847 | duprintf("translate_table: %u not %u entries\n", |
| 855 | i, number); | 848 | i, repl->num_entries); |
| 856 | return -EINVAL; | 849 | return -EINVAL; |
| 857 | } | 850 | } |
| 858 | 851 | ||
| 859 | /* Check hooks all assigned */ | 852 | /* Check hooks all assigned */ |
| 860 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 853 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
| 861 | /* Only hooks which are valid */ | 854 | /* Only hooks which are valid */ |
| 862 | if (!(valid_hooks & (1 << i))) | 855 | if (!(repl->valid_hooks & (1 << i))) |
| 863 | continue; | 856 | continue; |
| 864 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 857 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
| 865 | duprintf("Invalid hook entry %u %u\n", | 858 | duprintf("Invalid hook entry %u %u\n", |
| 866 | i, hook_entries[i]); | 859 | i, repl->hook_entry[i]); |
| 867 | return -EINVAL; | 860 | return -EINVAL; |
| 868 | } | 861 | } |
| 869 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 862 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
| 870 | duprintf("Invalid underflow %u %u\n", | 863 | duprintf("Invalid underflow %u %u\n", |
| 871 | i, underflows[i]); | 864 | i, repl->underflow[i]); |
| 872 | return -EINVAL; | 865 | return -EINVAL; |
| 873 | } | 866 | } |
| 874 | } | 867 | } |
| 875 | 868 | ||
| 876 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | 869 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) |
| 877 | return -ELOOP; | 870 | return -ELOOP; |
| 878 | 871 | ||
| 879 | /* Finally, each sanity check must pass */ | 872 | /* Finally, each sanity check must pass */ |
| 880 | i = 0; | 873 | i = 0; |
| 881 | ret = IPT_ENTRY_ITERATE(entry0, newinfo->size, | 874 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 882 | find_check_entry, net, name, size, &i); | 875 | ret = find_check_entry(iter, net, repl->name, repl->size); |
| 876 | if (ret != 0) | ||
| 877 | break; | ||
| 878 | ++i; | ||
| 879 | } | ||
| 883 | 880 | ||
| 884 | if (ret != 0) { | 881 | if (ret != 0) { |
| 885 | IPT_ENTRY_ITERATE(entry0, newinfo->size, | 882 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 886 | cleanup_entry, net, &i); | 883 | if (i-- == 0) |
| 884 | break; | ||
| 885 | cleanup_entry(iter, net); | ||
| 886 | } | ||
| 887 | return ret; | 887 | return ret; |
| 888 | } | 888 | } |
| 889 | 889 | ||
| @@ -896,33 +896,11 @@ translate_table(struct net *net, | |||
| 896 | return ret; | 896 | return ret; |
| 897 | } | 897 | } |
| 898 | 898 | ||
| 899 | /* Gets counters. */ | ||
| 900 | static inline int | ||
| 901 | add_entry_to_counter(const struct ipt_entry *e, | ||
| 902 | struct xt_counters total[], | ||
| 903 | unsigned int *i) | ||
| 904 | { | ||
| 905 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
| 906 | |||
| 907 | (*i)++; | ||
| 908 | return 0; | ||
| 909 | } | ||
| 910 | |||
| 911 | static inline int | ||
| 912 | set_entry_to_counter(const struct ipt_entry *e, | ||
| 913 | struct ipt_counters total[], | ||
| 914 | unsigned int *i) | ||
| 915 | { | ||
| 916 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
| 917 | |||
| 918 | (*i)++; | ||
| 919 | return 0; | ||
| 920 | } | ||
| 921 | |||
| 922 | static void | 899 | static void |
| 923 | get_counters(const struct xt_table_info *t, | 900 | get_counters(const struct xt_table_info *t, |
| 924 | struct xt_counters counters[]) | 901 | struct xt_counters counters[]) |
| 925 | { | 902 | { |
| 903 | struct ipt_entry *iter; | ||
| 926 | unsigned int cpu; | 904 | unsigned int cpu; |
| 927 | unsigned int i; | 905 | unsigned int i; |
| 928 | unsigned int curcpu; | 906 | unsigned int curcpu; |
| @@ -938,22 +916,22 @@ get_counters(const struct xt_table_info *t, | |||
| 938 | curcpu = smp_processor_id(); | 916 | curcpu = smp_processor_id(); |
| 939 | 917 | ||
| 940 | i = 0; | 918 | i = 0; |
| 941 | IPT_ENTRY_ITERATE(t->entries[curcpu], | 919 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
| 942 | t->size, | 920 | SET_COUNTER(counters[i], iter->counters.bcnt, |
| 943 | set_entry_to_counter, | 921 | iter->counters.pcnt); |
| 944 | counters, | 922 | ++i; |
| 945 | &i); | 923 | } |
| 946 | 924 | ||
| 947 | for_each_possible_cpu(cpu) { | 925 | for_each_possible_cpu(cpu) { |
| 948 | if (cpu == curcpu) | 926 | if (cpu == curcpu) |
| 949 | continue; | 927 | continue; |
| 950 | i = 0; | 928 | i = 0; |
| 951 | xt_info_wrlock(cpu); | 929 | xt_info_wrlock(cpu); |
| 952 | IPT_ENTRY_ITERATE(t->entries[cpu], | 930 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
| 953 | t->size, | 931 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
| 954 | add_entry_to_counter, | 932 | iter->counters.pcnt); |
| 955 | counters, | 933 | ++i; /* macro does multi eval of i */ |
| 956 | &i); | 934 | } |
| 957 | xt_info_wrunlock(cpu); | 935 | xt_info_wrunlock(cpu); |
| 958 | } | 936 | } |
| 959 | local_bh_enable(); | 937 | local_bh_enable(); |
| @@ -1072,24 +1050,19 @@ static int compat_standard_to_user(void __user *dst, const void *src) | |||
| 1072 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; | 1050 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; |
| 1073 | } | 1051 | } |
| 1074 | 1052 | ||
| 1075 | static inline int | ||
| 1076 | compat_calc_match(const struct ipt_entry_match *m, int *size) | ||
| 1077 | { | ||
| 1078 | *size += xt_compat_match_offset(m->u.kernel.match); | ||
| 1079 | return 0; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | static int compat_calc_entry(const struct ipt_entry *e, | 1053 | static int compat_calc_entry(const struct ipt_entry *e, |
| 1083 | const struct xt_table_info *info, | 1054 | const struct xt_table_info *info, |
| 1084 | const void *base, struct xt_table_info *newinfo) | 1055 | const void *base, struct xt_table_info *newinfo) |
| 1085 | { | 1056 | { |
| 1057 | const struct xt_entry_match *ematch; | ||
| 1086 | const struct ipt_entry_target *t; | 1058 | const struct ipt_entry_target *t; |
| 1087 | unsigned int entry_offset; | 1059 | unsigned int entry_offset; |
| 1088 | int off, i, ret; | 1060 | int off, i, ret; |
| 1089 | 1061 | ||
| 1090 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1062 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
| 1091 | entry_offset = (void *)e - base; | 1063 | entry_offset = (void *)e - base; |
| 1092 | IPT_MATCH_ITERATE(e, compat_calc_match, &off); | 1064 | xt_ematch_foreach(ematch, e) |
| 1065 | off += xt_compat_match_offset(ematch->u.kernel.match); | ||
| 1093 | t = ipt_get_target_c(e); | 1066 | t = ipt_get_target_c(e); |
| 1094 | off += xt_compat_target_offset(t->u.kernel.target); | 1067 | off += xt_compat_target_offset(t->u.kernel.target); |
| 1095 | newinfo->size -= off; | 1068 | newinfo->size -= off; |
| @@ -1111,7 +1084,9 @@ static int compat_calc_entry(const struct ipt_entry *e, | |||
| 1111 | static int compat_table_info(const struct xt_table_info *info, | 1084 | static int compat_table_info(const struct xt_table_info *info, |
| 1112 | struct xt_table_info *newinfo) | 1085 | struct xt_table_info *newinfo) |
| 1113 | { | 1086 | { |
| 1087 | struct ipt_entry *iter; | ||
| 1114 | void *loc_cpu_entry; | 1088 | void *loc_cpu_entry; |
| 1089 | int ret; | ||
| 1115 | 1090 | ||
| 1116 | if (!newinfo || !info) | 1091 | if (!newinfo || !info) |
| 1117 | return -EINVAL; | 1092 | return -EINVAL; |
| @@ -1120,9 +1095,12 @@ static int compat_table_info(const struct xt_table_info *info, | |||
| 1120 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 1095 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
| 1121 | newinfo->initial_entries = 0; | 1096 | newinfo->initial_entries = 0; |
| 1122 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 1097 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
| 1123 | return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size, | 1098 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
| 1124 | compat_calc_entry, info, loc_cpu_entry, | 1099 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
| 1125 | newinfo); | 1100 | if (ret != 0) |
| 1101 | return ret; | ||
| 1102 | } | ||
| 1103 | return 0; | ||
| 1126 | } | 1104 | } |
| 1127 | #endif | 1105 | #endif |
| 1128 | 1106 | ||
| @@ -1236,6 +1214,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
| 1236 | struct xt_table_info *oldinfo; | 1214 | struct xt_table_info *oldinfo; |
| 1237 | struct xt_counters *counters; | 1215 | struct xt_counters *counters; |
| 1238 | void *loc_cpu_old_entry; | 1216 | void *loc_cpu_old_entry; |
| 1217 | struct ipt_entry *iter; | ||
| 1239 | 1218 | ||
| 1240 | ret = 0; | 1219 | ret = 0; |
| 1241 | counters = vmalloc(num_counters * sizeof(struct xt_counters)); | 1220 | counters = vmalloc(num_counters * sizeof(struct xt_counters)); |
| @@ -1278,8 +1257,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
| 1278 | 1257 | ||
| 1279 | /* Decrease module usage counts and free resource */ | 1258 | /* Decrease module usage counts and free resource */ |
| 1280 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1259 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
| 1281 | IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1260 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
| 1282 | net, NULL); | 1261 | cleanup_entry(iter, net); |
| 1262 | |||
| 1283 | xt_free_table_info(oldinfo); | 1263 | xt_free_table_info(oldinfo); |
| 1284 | if (copy_to_user(counters_ptr, counters, | 1264 | if (copy_to_user(counters_ptr, counters, |
| 1285 | sizeof(struct xt_counters) * num_counters) != 0) | 1265 | sizeof(struct xt_counters) * num_counters) != 0) |
| @@ -1304,6 +1284,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
| 1304 | struct ipt_replace tmp; | 1284 | struct ipt_replace tmp; |
| 1305 | struct xt_table_info *newinfo; | 1285 | struct xt_table_info *newinfo; |
| 1306 | void *loc_cpu_entry; | 1286 | void *loc_cpu_entry; |
| 1287 | struct ipt_entry *iter; | ||
| 1307 | 1288 | ||
| 1308 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1289 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
| 1309 | return -EFAULT; | 1290 | return -EFAULT; |
| @@ -1324,9 +1305,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
| 1324 | goto free_newinfo; | 1305 | goto free_newinfo; |
| 1325 | } | 1306 | } |
| 1326 | 1307 | ||
| 1327 | ret = translate_table(net, tmp.name, tmp.valid_hooks, | 1308 | ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); |
| 1328 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
| 1329 | tmp.hook_entry, tmp.underflow); | ||
| 1330 | if (ret != 0) | 1309 | if (ret != 0) |
| 1331 | goto free_newinfo; | 1310 | goto free_newinfo; |
| 1332 | 1311 | ||
| @@ -1339,25 +1318,13 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
| 1339 | return 0; | 1318 | return 0; |
| 1340 | 1319 | ||
| 1341 | free_newinfo_untrans: | 1320 | free_newinfo_untrans: |
| 1342 | IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1321 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
| 1322 | cleanup_entry(iter, net); | ||
| 1343 | free_newinfo: | 1323 | free_newinfo: |
| 1344 | xt_free_table_info(newinfo); | 1324 | xt_free_table_info(newinfo); |
| 1345 | return ret; | 1325 | return ret; |
| 1346 | } | 1326 | } |
| 1347 | 1327 | ||
| 1348 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 1349 | * and everything is OK. */ | ||
| 1350 | static int | ||
| 1351 | add_counter_to_entry(struct ipt_entry *e, | ||
| 1352 | const struct xt_counters addme[], | ||
| 1353 | unsigned int *i) | ||
| 1354 | { | ||
| 1355 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 1356 | |||
| 1357 | (*i)++; | ||
| 1358 | return 0; | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | static int | 1328 | static int |
| 1362 | do_add_counters(struct net *net, const void __user *user, | 1329 | do_add_counters(struct net *net, const void __user *user, |
| 1363 | unsigned int len, int compat) | 1330 | unsigned int len, int compat) |
| @@ -1373,6 +1340,7 @@ do_add_counters(struct net *net, const void __user *user, | |||
| 1373 | const struct xt_table_info *private; | 1340 | const struct xt_table_info *private; |
| 1374 | int ret = 0; | 1341 | int ret = 0; |
| 1375 | void *loc_cpu_entry; | 1342 | void *loc_cpu_entry; |
| 1343 | struct ipt_entry *iter; | ||
| 1376 | #ifdef CONFIG_COMPAT | 1344 | #ifdef CONFIG_COMPAT |
| 1377 | struct compat_xt_counters_info compat_tmp; | 1345 | struct compat_xt_counters_info compat_tmp; |
| 1378 | 1346 | ||
| @@ -1430,11 +1398,10 @@ do_add_counters(struct net *net, const void __user *user, | |||
| 1430 | curcpu = smp_processor_id(); | 1398 | curcpu = smp_processor_id(); |
| 1431 | loc_cpu_entry = private->entries[curcpu]; | 1399 | loc_cpu_entry = private->entries[curcpu]; |
| 1432 | xt_info_wrlock(curcpu); | 1400 | xt_info_wrlock(curcpu); |
| 1433 | IPT_ENTRY_ITERATE(loc_cpu_entry, | 1401 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
| 1434 | private->size, | 1402 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
| 1435 | add_counter_to_entry, | 1403 | ++i; |
| 1436 | paddc, | 1404 | } |
| 1437 | &i); | ||
| 1438 | xt_info_wrunlock(curcpu); | 1405 | xt_info_wrunlock(curcpu); |
| 1439 | unlock_up_free: | 1406 | unlock_up_free: |
| 1440 | local_bh_enable(); | 1407 | local_bh_enable(); |
| @@ -1462,45 +1429,40 @@ struct compat_ipt_replace { | |||
| 1462 | static int | 1429 | static int |
| 1463 | compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, | 1430 | compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, |
| 1464 | unsigned int *size, struct xt_counters *counters, | 1431 | unsigned int *size, struct xt_counters *counters, |
| 1465 | unsigned int *i) | 1432 | unsigned int i) |
| 1466 | { | 1433 | { |
| 1467 | struct ipt_entry_target *t; | 1434 | struct ipt_entry_target *t; |
| 1468 | struct compat_ipt_entry __user *ce; | 1435 | struct compat_ipt_entry __user *ce; |
| 1469 | u_int16_t target_offset, next_offset; | 1436 | u_int16_t target_offset, next_offset; |
| 1470 | compat_uint_t origsize; | 1437 | compat_uint_t origsize; |
| 1471 | int ret; | 1438 | const struct xt_entry_match *ematch; |
| 1439 | int ret = 0; | ||
| 1472 | 1440 | ||
| 1473 | ret = -EFAULT; | ||
| 1474 | origsize = *size; | 1441 | origsize = *size; |
| 1475 | ce = (struct compat_ipt_entry __user *)*dstptr; | 1442 | ce = (struct compat_ipt_entry __user *)*dstptr; |
| 1476 | if (copy_to_user(ce, e, sizeof(struct ipt_entry))) | 1443 | if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || |
| 1477 | goto out; | 1444 | copy_to_user(&ce->counters, &counters[i], |
| 1478 | 1445 | sizeof(counters[i])) != 0) | |
| 1479 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1446 | return -EFAULT; |
| 1480 | goto out; | ||
| 1481 | 1447 | ||
| 1482 | *dstptr += sizeof(struct compat_ipt_entry); | 1448 | *dstptr += sizeof(struct compat_ipt_entry); |
| 1483 | *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1449 | *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
| 1484 | 1450 | ||
| 1485 | ret = IPT_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); | 1451 | xt_ematch_foreach(ematch, e) { |
| 1452 | ret = xt_compat_match_to_user(ematch, dstptr, size); | ||
| 1453 | if (ret != 0) | ||
| 1454 | return ret; | ||
| 1455 | } | ||
| 1486 | target_offset = e->target_offset - (origsize - *size); | 1456 | target_offset = e->target_offset - (origsize - *size); |
| 1487 | if (ret) | ||
| 1488 | goto out; | ||
| 1489 | t = ipt_get_target(e); | 1457 | t = ipt_get_target(e); |
| 1490 | ret = xt_compat_target_to_user(t, dstptr, size); | 1458 | ret = xt_compat_target_to_user(t, dstptr, size); |
| 1491 | if (ret) | 1459 | if (ret) |
| 1492 | goto out; | 1460 | return ret; |
| 1493 | ret = -EFAULT; | ||
| 1494 | next_offset = e->next_offset - (origsize - *size); | 1461 | next_offset = e->next_offset - (origsize - *size); |
| 1495 | if (put_user(target_offset, &ce->target_offset)) | 1462 | if (put_user(target_offset, &ce->target_offset) != 0 || |
| 1496 | goto out; | 1463 | put_user(next_offset, &ce->next_offset) != 0) |
| 1497 | if (put_user(next_offset, &ce->next_offset)) | 1464 | return -EFAULT; |
| 1498 | goto out; | ||
| 1499 | |||
| 1500 | (*i)++; | ||
| 1501 | return 0; | 1465 | return 0; |
| 1502 | out: | ||
| 1503 | return ret; | ||
| 1504 | } | 1466 | } |
| 1505 | 1467 | ||
| 1506 | static int | 1468 | static int |
| @@ -1508,7 +1470,7 @@ compat_find_calc_match(struct ipt_entry_match *m, | |||
| 1508 | const char *name, | 1470 | const char *name, |
| 1509 | const struct ipt_ip *ip, | 1471 | const struct ipt_ip *ip, |
| 1510 | unsigned int hookmask, | 1472 | unsigned int hookmask, |
| 1511 | int *size, unsigned int *i) | 1473 | int *size) |
| 1512 | { | 1474 | { |
| 1513 | struct xt_match *match; | 1475 | struct xt_match *match; |
| 1514 | 1476 | ||
| @@ -1522,34 +1484,19 @@ compat_find_calc_match(struct ipt_entry_match *m, | |||
| 1522 | } | 1484 | } |
| 1523 | m->u.kernel.match = match; | 1485 | m->u.kernel.match = match; |
| 1524 | *size += xt_compat_match_offset(match); | 1486 | *size += xt_compat_match_offset(match); |
| 1525 | |||
| 1526 | (*i)++; | ||
| 1527 | return 0; | 1487 | return 0; |
| 1528 | } | 1488 | } |
| 1529 | 1489 | ||
| 1530 | static int | 1490 | static void compat_release_entry(struct compat_ipt_entry *e) |
| 1531 | compat_release_match(struct ipt_entry_match *m, unsigned int *i) | ||
| 1532 | { | ||
| 1533 | if (i && (*i)-- == 0) | ||
| 1534 | return 1; | ||
| 1535 | |||
| 1536 | module_put(m->u.kernel.match->me); | ||
| 1537 | return 0; | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | static int | ||
| 1541 | compat_release_entry(struct compat_ipt_entry *e, unsigned int *i) | ||
| 1542 | { | 1491 | { |
| 1543 | struct ipt_entry_target *t; | 1492 | struct ipt_entry_target *t; |
| 1544 | 1493 | struct xt_entry_match *ematch; | |
| 1545 | if (i && (*i)-- == 0) | ||
| 1546 | return 1; | ||
| 1547 | 1494 | ||
| 1548 | /* Cleanup all matches */ | 1495 | /* Cleanup all matches */ |
| 1549 | COMPAT_IPT_MATCH_ITERATE(e, compat_release_match, NULL); | 1496 | xt_ematch_foreach(ematch, e) |
| 1497 | module_put(ematch->u.kernel.match->me); | ||
| 1550 | t = compat_ipt_get_target(e); | 1498 | t = compat_ipt_get_target(e); |
| 1551 | module_put(t->u.kernel.target->me); | 1499 | module_put(t->u.kernel.target->me); |
| 1552 | return 0; | ||
| 1553 | } | 1500 | } |
| 1554 | 1501 | ||
| 1555 | static int | 1502 | static int |
| @@ -1560,9 +1507,9 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
| 1560 | const unsigned char *limit, | 1507 | const unsigned char *limit, |
| 1561 | const unsigned int *hook_entries, | 1508 | const unsigned int *hook_entries, |
| 1562 | const unsigned int *underflows, | 1509 | const unsigned int *underflows, |
| 1563 | unsigned int *i, | ||
| 1564 | const char *name) | 1510 | const char *name) |
| 1565 | { | 1511 | { |
| 1512 | struct xt_entry_match *ematch; | ||
| 1566 | struct ipt_entry_target *t; | 1513 | struct ipt_entry_target *t; |
| 1567 | struct xt_target *target; | 1514 | struct xt_target *target; |
| 1568 | unsigned int entry_offset; | 1515 | unsigned int entry_offset; |
| @@ -1591,10 +1538,13 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
| 1591 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1538 | off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
| 1592 | entry_offset = (void *)e - (void *)base; | 1539 | entry_offset = (void *)e - (void *)base; |
| 1593 | j = 0; | 1540 | j = 0; |
| 1594 | ret = COMPAT_IPT_MATCH_ITERATE(e, compat_find_calc_match, name, | 1541 | xt_ematch_foreach(ematch, e) { |
| 1595 | &e->ip, e->comefrom, &off, &j); | 1542 | ret = compat_find_calc_match(ematch, name, |
| 1596 | if (ret != 0) | 1543 | &e->ip, e->comefrom, &off); |
| 1597 | goto release_matches; | 1544 | if (ret != 0) |
| 1545 | goto release_matches; | ||
| 1546 | ++j; | ||
| 1547 | } | ||
| 1598 | 1548 | ||
| 1599 | t = compat_ipt_get_target(e); | 1549 | t = compat_ipt_get_target(e); |
| 1600 | target = try_then_request_module(xt_find_target(AF_INET, | 1550 | target = try_then_request_module(xt_find_target(AF_INET, |
| @@ -1626,14 +1576,16 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
| 1626 | /* Clear counters and comefrom */ | 1576 | /* Clear counters and comefrom */ |
| 1627 | memset(&e->counters, 0, sizeof(e->counters)); | 1577 | memset(&e->counters, 0, sizeof(e->counters)); |
| 1628 | e->comefrom = 0; | 1578 | e->comefrom = 0; |
| 1629 | |||
| 1630 | (*i)++; | ||
| 1631 | return 0; | 1579 | return 0; |
| 1632 | 1580 | ||
| 1633 | out: | 1581 | out: |
| 1634 | module_put(t->u.kernel.target->me); | 1582 | module_put(t->u.kernel.target->me); |
| 1635 | release_matches: | 1583 | release_matches: |
| 1636 | IPT_MATCH_ITERATE(e, compat_release_match, &j); | 1584 | xt_ematch_foreach(ematch, e) { |
| 1585 | if (j-- == 0) | ||
| 1586 | break; | ||
| 1587 | module_put(ematch->u.kernel.match->me); | ||
| 1588 | } | ||
| 1637 | return ret; | 1589 | return ret; |
| 1638 | } | 1590 | } |
| 1639 | 1591 | ||
| @@ -1647,6 +1599,7 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
| 1647 | struct ipt_entry *de; | 1599 | struct ipt_entry *de; |
| 1648 | unsigned int origsize; | 1600 | unsigned int origsize; |
| 1649 | int ret, h; | 1601 | int ret, h; |
| 1602 | struct xt_entry_match *ematch; | ||
| 1650 | 1603 | ||
| 1651 | ret = 0; | 1604 | ret = 0; |
| 1652 | origsize = *size; | 1605 | origsize = *size; |
| @@ -1657,10 +1610,11 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
| 1657 | *dstptr += sizeof(struct ipt_entry); | 1610 | *dstptr += sizeof(struct ipt_entry); |
| 1658 | *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1611 | *size += sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
| 1659 | 1612 | ||
| 1660 | ret = COMPAT_IPT_MATCH_ITERATE(e, xt_compat_match_from_user, | 1613 | xt_ematch_foreach(ematch, e) { |
| 1661 | dstptr, size); | 1614 | ret = xt_compat_match_from_user(ematch, dstptr, size); |
| 1662 | if (ret) | 1615 | if (ret != 0) |
| 1663 | return ret; | 1616 | return ret; |
| 1617 | } | ||
| 1664 | de->target_offset = e->target_offset - (origsize - *size); | 1618 | de->target_offset = e->target_offset - (origsize - *size); |
| 1665 | t = compat_ipt_get_target(e); | 1619 | t = compat_ipt_get_target(e); |
| 1666 | target = t->u.kernel.target; | 1620 | target = t->u.kernel.target; |
| @@ -1677,12 +1631,12 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
| 1677 | } | 1631 | } |
| 1678 | 1632 | ||
| 1679 | static int | 1633 | static int |
| 1680 | compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, | 1634 | compat_check_entry(struct ipt_entry *e, struct net *net, const char *name) |
| 1681 | unsigned int *i) | ||
| 1682 | { | 1635 | { |
| 1636 | struct xt_entry_match *ematch; | ||
| 1683 | struct xt_mtchk_param mtpar; | 1637 | struct xt_mtchk_param mtpar; |
| 1684 | unsigned int j; | 1638 | unsigned int j; |
| 1685 | int ret; | 1639 | int ret = 0; |
| 1686 | 1640 | ||
| 1687 | j = 0; | 1641 | j = 0; |
| 1688 | mtpar.net = net; | 1642 | mtpar.net = net; |
| @@ -1690,19 +1644,24 @@ compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
| 1690 | mtpar.entryinfo = &e->ip; | 1644 | mtpar.entryinfo = &e->ip; |
| 1691 | mtpar.hook_mask = e->comefrom; | 1645 | mtpar.hook_mask = e->comefrom; |
| 1692 | mtpar.family = NFPROTO_IPV4; | 1646 | mtpar.family = NFPROTO_IPV4; |
| 1693 | ret = IPT_MATCH_ITERATE(e, check_match, &mtpar, &j); | 1647 | xt_ematch_foreach(ematch, e) { |
| 1694 | if (ret) | 1648 | ret = check_match(ematch, &mtpar); |
| 1695 | goto cleanup_matches; | 1649 | if (ret != 0) |
| 1650 | goto cleanup_matches; | ||
| 1651 | ++j; | ||
| 1652 | } | ||
| 1696 | 1653 | ||
| 1697 | ret = check_target(e, net, name); | 1654 | ret = check_target(e, net, name); |
| 1698 | if (ret) | 1655 | if (ret) |
| 1699 | goto cleanup_matches; | 1656 | goto cleanup_matches; |
| 1700 | |||
| 1701 | (*i)++; | ||
| 1702 | return 0; | 1657 | return 0; |
| 1703 | 1658 | ||
| 1704 | cleanup_matches: | 1659 | cleanup_matches: |
| 1705 | IPT_MATCH_ITERATE(e, cleanup_match, net, &j); | 1660 | xt_ematch_foreach(ematch, e) { |
| 1661 | if (j-- == 0) | ||
| 1662 | break; | ||
| 1663 | cleanup_match(ematch, net); | ||
| 1664 | } | ||
| 1706 | return ret; | 1665 | return ret; |
| 1707 | } | 1666 | } |
| 1708 | 1667 | ||
| @@ -1720,6 +1679,8 @@ translate_compat_table(struct net *net, | |||
| 1720 | unsigned int i, j; | 1679 | unsigned int i, j; |
| 1721 | struct xt_table_info *newinfo, *info; | 1680 | struct xt_table_info *newinfo, *info; |
| 1722 | void *pos, *entry0, *entry1; | 1681 | void *pos, *entry0, *entry1; |
| 1682 | struct compat_ipt_entry *iter0; | ||
| 1683 | struct ipt_entry *iter1; | ||
| 1723 | unsigned int size; | 1684 | unsigned int size; |
| 1724 | int ret; | 1685 | int ret; |
| 1725 | 1686 | ||
| @@ -1738,13 +1699,14 @@ translate_compat_table(struct net *net, | |||
| 1738 | j = 0; | 1699 | j = 0; |
| 1739 | xt_compat_lock(AF_INET); | 1700 | xt_compat_lock(AF_INET); |
| 1740 | /* Walk through entries, checking offsets. */ | 1701 | /* Walk through entries, checking offsets. */ |
| 1741 | ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, | 1702 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1742 | check_compat_entry_size_and_hooks, | 1703 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
| 1743 | info, &size, entry0, | 1704 | entry0, entry0 + total_size, hook_entries, underflows, |
| 1744 | entry0 + total_size, | 1705 | name); |
| 1745 | hook_entries, underflows, &j, name); | 1706 | if (ret != 0) |
| 1746 | if (ret != 0) | 1707 | goto out_unlock; |
| 1747 | goto out_unlock; | 1708 | ++j; |
| 1709 | } | ||
| 1748 | 1710 | ||
| 1749 | ret = -EINVAL; | 1711 | ret = -EINVAL; |
| 1750 | if (j != number) { | 1712 | if (j != number) { |
| @@ -1783,9 +1745,12 @@ translate_compat_table(struct net *net, | |||
| 1783 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1745 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
| 1784 | pos = entry1; | 1746 | pos = entry1; |
| 1785 | size = total_size; | 1747 | size = total_size; |
| 1786 | ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, | 1748 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1787 | compat_copy_entry_from_user, | 1749 | ret = compat_copy_entry_from_user(iter0, &pos, |
| 1788 | &pos, &size, name, newinfo, entry1); | 1750 | &size, name, newinfo, entry1); |
| 1751 | if (ret != 0) | ||
| 1752 | break; | ||
| 1753 | } | ||
| 1789 | xt_compat_flush_offsets(AF_INET); | 1754 | xt_compat_flush_offsets(AF_INET); |
| 1790 | xt_compat_unlock(AF_INET); | 1755 | xt_compat_unlock(AF_INET); |
| 1791 | if (ret) | 1756 | if (ret) |
| @@ -1796,13 +1761,32 @@ translate_compat_table(struct net *net, | |||
| 1796 | goto free_newinfo; | 1761 | goto free_newinfo; |
| 1797 | 1762 | ||
| 1798 | i = 0; | 1763 | i = 0; |
| 1799 | ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1764 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
| 1800 | net, name, &i); | 1765 | ret = compat_check_entry(iter1, net, name); |
| 1766 | if (ret != 0) | ||
| 1767 | break; | ||
| 1768 | ++i; | ||
| 1769 | } | ||
| 1801 | if (ret) { | 1770 | if (ret) { |
| 1771 | /* | ||
| 1772 | * The first i matches need cleanup_entry (calls ->destroy) | ||
| 1773 | * because they had called ->check already. The other j-i | ||
| 1774 | * entries need only release. | ||
| 1775 | */ | ||
| 1776 | int skip = i; | ||
| 1802 | j -= i; | 1777 | j -= i; |
| 1803 | COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1778 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
| 1804 | compat_release_entry, &j); | 1779 | if (skip-- > 0) |
| 1805 | IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, net, &i); | 1780 | continue; |
| 1781 | if (j-- == 0) | ||
| 1782 | break; | ||
| 1783 | compat_release_entry(iter0); | ||
| 1784 | } | ||
| 1785 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
| 1786 | if (i-- == 0) | ||
| 1787 | break; | ||
| 1788 | cleanup_entry(iter1, net); | ||
| 1789 | } | ||
| 1806 | xt_free_table_info(newinfo); | 1790 | xt_free_table_info(newinfo); |
| 1807 | return ret; | 1791 | return ret; |
| 1808 | } | 1792 | } |
| @@ -1820,7 +1804,11 @@ translate_compat_table(struct net *net, | |||
| 1820 | free_newinfo: | 1804 | free_newinfo: |
| 1821 | xt_free_table_info(newinfo); | 1805 | xt_free_table_info(newinfo); |
| 1822 | out: | 1806 | out: |
| 1823 | COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1807 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1808 | if (j-- == 0) | ||
| 1809 | break; | ||
| 1810 | compat_release_entry(iter0); | ||
| 1811 | } | ||
| 1824 | return ret; | 1812 | return ret; |
| 1825 | out_unlock: | 1813 | out_unlock: |
| 1826 | xt_compat_flush_offsets(AF_INET); | 1814 | xt_compat_flush_offsets(AF_INET); |
| @@ -1835,6 +1823,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1835 | struct compat_ipt_replace tmp; | 1823 | struct compat_ipt_replace tmp; |
| 1836 | struct xt_table_info *newinfo; | 1824 | struct xt_table_info *newinfo; |
| 1837 | void *loc_cpu_entry; | 1825 | void *loc_cpu_entry; |
| 1826 | struct ipt_entry *iter; | ||
| 1838 | 1827 | ||
| 1839 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1828 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
| 1840 | return -EFAULT; | 1829 | return -EFAULT; |
| @@ -1873,7 +1862,8 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1873 | return 0; | 1862 | return 0; |
| 1874 | 1863 | ||
| 1875 | free_newinfo_untrans: | 1864 | free_newinfo_untrans: |
| 1876 | IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1865 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
| 1866 | cleanup_entry(iter, net); | ||
| 1877 | free_newinfo: | 1867 | free_newinfo: |
| 1878 | xt_free_table_info(newinfo); | 1868 | xt_free_table_info(newinfo); |
| 1879 | return ret; | 1869 | return ret; |
| @@ -1922,6 +1912,7 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
| 1922 | int ret = 0; | 1912 | int ret = 0; |
| 1923 | const void *loc_cpu_entry; | 1913 | const void *loc_cpu_entry; |
| 1924 | unsigned int i = 0; | 1914 | unsigned int i = 0; |
| 1915 | struct ipt_entry *iter; | ||
| 1925 | 1916 | ||
| 1926 | counters = alloc_counters(table); | 1917 | counters = alloc_counters(table); |
| 1927 | if (IS_ERR(counters)) | 1918 | if (IS_ERR(counters)) |
| @@ -1934,9 +1925,12 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
| 1934 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1925 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| 1935 | pos = userptr; | 1926 | pos = userptr; |
| 1936 | size = total_size; | 1927 | size = total_size; |
| 1937 | ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1928 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
| 1938 | compat_copy_entry_to_user, | 1929 | ret = compat_copy_entry_to_user(iter, &pos, |
| 1939 | &pos, &size, counters, &i); | 1930 | &size, counters, i++); |
| 1931 | if (ret != 0) | ||
| 1932 | break; | ||
| 1933 | } | ||
| 1940 | 1934 | ||
| 1941 | vfree(counters); | 1935 | vfree(counters); |
| 1942 | return ret; | 1936 | return ret; |
| @@ -2110,11 +2104,7 @@ struct xt_table *ipt_register_table(struct net *net, | |||
| 2110 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 2104 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
| 2111 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 2105 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
| 2112 | 2106 | ||
| 2113 | ret = translate_table(net, table->name, table->valid_hooks, | 2107 | ret = translate_table(net, newinfo, loc_cpu_entry, repl); |
| 2114 | newinfo, loc_cpu_entry, repl->size, | ||
| 2115 | repl->num_entries, | ||
| 2116 | repl->hook_entry, | ||
| 2117 | repl->underflow); | ||
| 2118 | if (ret != 0) | 2108 | if (ret != 0) |
| 2119 | goto out_free; | 2109 | goto out_free; |
| 2120 | 2110 | ||
| @@ -2137,12 +2127,14 @@ void ipt_unregister_table(struct net *net, struct xt_table *table) | |||
| 2137 | struct xt_table_info *private; | 2127 | struct xt_table_info *private; |
| 2138 | void *loc_cpu_entry; | 2128 | void *loc_cpu_entry; |
| 2139 | struct module *table_owner = table->me; | 2129 | struct module *table_owner = table->me; |
| 2130 | struct ipt_entry *iter; | ||
| 2140 | 2131 | ||
| 2141 | private = xt_unregister_table(table); | 2132 | private = xt_unregister_table(table); |
| 2142 | 2133 | ||
| 2143 | /* Decrease module usage counts and free resources */ | 2134 | /* Decrease module usage counts and free resources */ |
| 2144 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 2135 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| 2145 | IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, net, NULL); | 2136 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
| 2137 | cleanup_entry(iter, net); | ||
| 2146 | if (private->number > private->initial_entries) | 2138 | if (private->number > private->initial_entries) |
| 2147 | module_put(table_owner); | 2139 | module_put(table_owner); |
| 2148 | xt_free_table_info(private); | 2140 | xt_free_table_info(private); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 4185099c2943..f7042869198e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
| @@ -318,6 +318,7 @@ static void trace_packet(const struct sk_buff *skb, | |||
| 318 | const void *table_base; | 318 | const void *table_base; |
| 319 | const struct ip6t_entry *root; | 319 | const struct ip6t_entry *root; |
| 320 | const char *hookname, *chainname, *comment; | 320 | const char *hookname, *chainname, *comment; |
| 321 | const struct ip6t_entry *iter; | ||
| 321 | unsigned int rulenum = 0; | 322 | unsigned int rulenum = 0; |
| 322 | 323 | ||
| 323 | table_base = private->entries[smp_processor_id()]; | 324 | table_base = private->entries[smp_processor_id()]; |
| @@ -326,10 +327,10 @@ static void trace_packet(const struct sk_buff *skb, | |||
| 326 | hookname = chainname = hooknames[hook]; | 327 | hookname = chainname = hooknames[hook]; |
| 327 | comment = comments[NF_IP6_TRACE_COMMENT_RULE]; | 328 | comment = comments[NF_IP6_TRACE_COMMENT_RULE]; |
| 328 | 329 | ||
| 329 | IP6T_ENTRY_ITERATE(root, | 330 | xt_entry_foreach(iter, root, private->size - private->hook_entry[hook]) |
| 330 | private->size - private->hook_entry[hook], | 331 | if (get_chainname_rulenum(iter, e, hookname, |
| 331 | get_chainname_rulenum, | 332 | &chainname, &comment, &rulenum) != 0) |
| 332 | e, hookname, &chainname, &comment, &rulenum); | 333 | break; |
| 333 | 334 | ||
| 334 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, | 335 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, |
| 335 | "TRACE: %s:%s:%s:%u ", | 336 | "TRACE: %s:%s:%s:%u ", |
| @@ -392,16 +393,21 @@ ip6t_do_table(struct sk_buff *skb, | |||
| 392 | 393 | ||
| 393 | do { | 394 | do { |
| 394 | const struct ip6t_entry_target *t; | 395 | const struct ip6t_entry_target *t; |
| 396 | const struct xt_entry_match *ematch; | ||
| 395 | 397 | ||
| 396 | IP_NF_ASSERT(e); | 398 | IP_NF_ASSERT(e); |
| 397 | IP_NF_ASSERT(back); | 399 | IP_NF_ASSERT(back); |
| 398 | if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, | 400 | if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, |
| 399 | &mtpar.thoff, &mtpar.fragoff, &hotdrop) || | 401 | &mtpar.thoff, &mtpar.fragoff, &hotdrop)) { |
| 400 | IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { | 402 | no_match: |
| 401 | e = ip6t_next_entry(e); | 403 | e = ip6t_next_entry(e); |
| 402 | continue; | 404 | continue; |
| 403 | } | 405 | } |
| 404 | 406 | ||
| 407 | xt_ematch_foreach(ematch, e) | ||
| 408 | if (do_match(ematch, skb, &mtpar) != 0) | ||
| 409 | goto no_match; | ||
| 410 | |||
| 405 | ADD_COUNTER(e->counters, | 411 | ADD_COUNTER(e->counters, |
| 406 | ntohs(ipv6_hdr(skb)->payload_len) + | 412 | ntohs(ipv6_hdr(skb)->payload_len) + |
| 407 | sizeof(struct ipv6hdr), 1); | 413 | sizeof(struct ipv6hdr), 1); |
| @@ -597,14 +603,10 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
| 597 | return 1; | 603 | return 1; |
| 598 | } | 604 | } |
| 599 | 605 | ||
| 600 | static int | 606 | static void cleanup_match(struct ip6t_entry_match *m, struct net *net) |
| 601 | cleanup_match(struct ip6t_entry_match *m, struct net *net, unsigned int *i) | ||
| 602 | { | 607 | { |
| 603 | struct xt_mtdtor_param par; | 608 | struct xt_mtdtor_param par; |
| 604 | 609 | ||
| 605 | if (i && (*i)-- == 0) | ||
| 606 | return 1; | ||
| 607 | |||
| 608 | par.net = net; | 610 | par.net = net; |
| 609 | par.match = m->u.kernel.match; | 611 | par.match = m->u.kernel.match; |
| 610 | par.matchinfo = m->data; | 612 | par.matchinfo = m->data; |
| @@ -612,7 +614,6 @@ cleanup_match(struct ip6t_entry_match *m, struct net *net, unsigned int *i) | |||
| 612 | if (par.match->destroy != NULL) | 614 | if (par.match->destroy != NULL) |
| 613 | par.match->destroy(&par); | 615 | par.match->destroy(&par); |
| 614 | module_put(par.match->me); | 616 | module_put(par.match->me); |
| 615 | return 0; | ||
| 616 | } | 617 | } |
| 617 | 618 | ||
| 618 | static int | 619 | static int |
| @@ -636,8 +637,7 @@ check_entry(const struct ip6t_entry *e, const char *name) | |||
| 636 | return 0; | 637 | return 0; |
| 637 | } | 638 | } |
| 638 | 639 | ||
| 639 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | 640 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) |
| 640 | unsigned int *i) | ||
| 641 | { | 641 | { |
| 642 | const struct ip6t_ip6 *ipv6 = par->entryinfo; | 642 | const struct ip6t_ip6 *ipv6 = par->entryinfo; |
| 643 | int ret; | 643 | int ret; |
| @@ -652,13 +652,11 @@ static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | |||
| 652 | par.match->name); | 652 | par.match->name); |
| 653 | return ret; | 653 | return ret; |
| 654 | } | 654 | } |
| 655 | ++*i; | ||
| 656 | return 0; | 655 | return 0; |
| 657 | } | 656 | } |
| 658 | 657 | ||
| 659 | static int | 658 | static int |
| 660 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | 659 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) |
| 661 | unsigned int *i) | ||
| 662 | { | 660 | { |
| 663 | struct xt_match *match; | 661 | struct xt_match *match; |
| 664 | int ret; | 662 | int ret; |
| @@ -672,7 +670,7 @@ find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | |||
| 672 | } | 670 | } |
| 673 | m->u.kernel.match = match; | 671 | m->u.kernel.match = match; |
| 674 | 672 | ||
| 675 | ret = check_match(m, par, i); | 673 | ret = check_match(m, par); |
| 676 | if (ret) | 674 | if (ret) |
| 677 | goto err; | 675 | goto err; |
| 678 | 676 | ||
| @@ -709,13 +707,14 @@ static int check_target(struct ip6t_entry *e, struct net *net, const char *name) | |||
| 709 | 707 | ||
| 710 | static int | 708 | static int |
| 711 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | 709 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, |
| 712 | unsigned int size, unsigned int *i) | 710 | unsigned int size) |
| 713 | { | 711 | { |
| 714 | struct ip6t_entry_target *t; | 712 | struct ip6t_entry_target *t; |
| 715 | struct xt_target *target; | 713 | struct xt_target *target; |
| 716 | int ret; | 714 | int ret; |
| 717 | unsigned int j; | 715 | unsigned int j; |
| 718 | struct xt_mtchk_param mtpar; | 716 | struct xt_mtchk_param mtpar; |
| 717 | struct xt_entry_match *ematch; | ||
| 719 | 718 | ||
| 720 | ret = check_entry(e, name); | 719 | ret = check_entry(e, name); |
| 721 | if (ret) | 720 | if (ret) |
| @@ -727,9 +726,12 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | |||
| 727 | mtpar.entryinfo = &e->ipv6; | 726 | mtpar.entryinfo = &e->ipv6; |
| 728 | mtpar.hook_mask = e->comefrom; | 727 | mtpar.hook_mask = e->comefrom; |
| 729 | mtpar.family = NFPROTO_IPV6; | 728 | mtpar.family = NFPROTO_IPV6; |
| 730 | ret = IP6T_MATCH_ITERATE(e, find_check_match, &mtpar, &j); | 729 | xt_ematch_foreach(ematch, e) { |
| 731 | if (ret != 0) | 730 | ret = find_check_match(ematch, &mtpar); |
| 732 | goto cleanup_matches; | 731 | if (ret != 0) |
| 732 | goto cleanup_matches; | ||
| 733 | ++j; | ||
| 734 | } | ||
| 733 | 735 | ||
| 734 | t = ip6t_get_target(e); | 736 | t = ip6t_get_target(e); |
| 735 | target = try_then_request_module(xt_find_target(AF_INET6, | 737 | target = try_then_request_module(xt_find_target(AF_INET6, |
| @@ -746,13 +748,15 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | |||
| 746 | ret = check_target(e, net, name); | 748 | ret = check_target(e, net, name); |
| 747 | if (ret) | 749 | if (ret) |
| 748 | goto err; | 750 | goto err; |
| 749 | |||
| 750 | (*i)++; | ||
| 751 | return 0; | 751 | return 0; |
| 752 | err: | 752 | err: |
| 753 | module_put(t->u.kernel.target->me); | 753 | module_put(t->u.kernel.target->me); |
| 754 | cleanup_matches: | 754 | cleanup_matches: |
| 755 | IP6T_MATCH_ITERATE(e, cleanup_match, net, &j); | 755 | xt_ematch_foreach(ematch, e) { |
| 756 | if (j-- == 0) | ||
| 757 | break; | ||
| 758 | cleanup_match(ematch, net); | ||
| 759 | } | ||
| 756 | return ret; | 760 | return ret; |
| 757 | } | 761 | } |
| 758 | 762 | ||
| @@ -778,8 +782,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
| 778 | const unsigned char *limit, | 782 | const unsigned char *limit, |
| 779 | const unsigned int *hook_entries, | 783 | const unsigned int *hook_entries, |
| 780 | const unsigned int *underflows, | 784 | const unsigned int *underflows, |
| 781 | unsigned int valid_hooks, | 785 | unsigned int valid_hooks) |
| 782 | unsigned int *i) | ||
| 783 | { | 786 | { |
| 784 | unsigned int h; | 787 | unsigned int h; |
| 785 | 788 | ||
| @@ -816,22 +819,18 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
| 816 | /* Clear counters and comefrom */ | 819 | /* Clear counters and comefrom */ |
| 817 | e->counters = ((struct xt_counters) { 0, 0 }); | 820 | e->counters = ((struct xt_counters) { 0, 0 }); |
| 818 | e->comefrom = 0; | 821 | e->comefrom = 0; |
| 819 | |||
| 820 | (*i)++; | ||
| 821 | return 0; | 822 | return 0; |
| 822 | } | 823 | } |
| 823 | 824 | ||
| 824 | static int | 825 | static void cleanup_entry(struct ip6t_entry *e, struct net *net) |
| 825 | cleanup_entry(struct ip6t_entry *e, struct net *net, unsigned int *i) | ||
| 826 | { | 826 | { |
| 827 | struct xt_tgdtor_param par; | 827 | struct xt_tgdtor_param par; |
| 828 | struct ip6t_entry_target *t; | 828 | struct ip6t_entry_target *t; |
| 829 | 829 | struct xt_entry_match *ematch; | |
| 830 | if (i && (*i)-- == 0) | ||
| 831 | return 1; | ||
| 832 | 830 | ||
| 833 | /* Cleanup all matches */ | 831 | /* Cleanup all matches */ |
| 834 | IP6T_MATCH_ITERATE(e, cleanup_match, net, NULL); | 832 | xt_ematch_foreach(ematch, e) |
| 833 | cleanup_match(ematch, net); | ||
| 835 | t = ip6t_get_target(e); | 834 | t = ip6t_get_target(e); |
| 836 | 835 | ||
| 837 | par.net = net; | 836 | par.net = net; |
| @@ -841,27 +840,20 @@ cleanup_entry(struct ip6t_entry *e, struct net *net, unsigned int *i) | |||
| 841 | if (par.target->destroy != NULL) | 840 | if (par.target->destroy != NULL) |
| 842 | par.target->destroy(&par); | 841 | par.target->destroy(&par); |
| 843 | module_put(par.target->me); | 842 | module_put(par.target->me); |
| 844 | return 0; | ||
| 845 | } | 843 | } |
| 846 | 844 | ||
| 847 | /* Checks and translates the user-supplied table segment (held in | 845 | /* Checks and translates the user-supplied table segment (held in |
| 848 | newinfo) */ | 846 | newinfo) */ |
| 849 | static int | 847 | static int |
| 850 | translate_table(struct net *net, | 848 | translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, |
| 851 | const char *name, | 849 | const struct ip6t_replace *repl) |
| 852 | unsigned int valid_hooks, | ||
| 853 | struct xt_table_info *newinfo, | ||
| 854 | void *entry0, | ||
| 855 | unsigned int size, | ||
| 856 | unsigned int number, | ||
| 857 | const unsigned int *hook_entries, | ||
| 858 | const unsigned int *underflows) | ||
| 859 | { | 850 | { |
| 851 | struct ip6t_entry *iter; | ||
| 860 | unsigned int i; | 852 | unsigned int i; |
| 861 | int ret; | 853 | int ret = 0; |
| 862 | 854 | ||
| 863 | newinfo->size = size; | 855 | newinfo->size = repl->size; |
| 864 | newinfo->number = number; | 856 | newinfo->number = repl->num_entries; |
| 865 | 857 | ||
| 866 | /* Init all hooks to impossible value. */ | 858 | /* Init all hooks to impossible value. */ |
| 867 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 859 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
| @@ -872,49 +864,56 @@ translate_table(struct net *net, | |||
| 872 | duprintf("translate_table: size %u\n", newinfo->size); | 864 | duprintf("translate_table: size %u\n", newinfo->size); |
| 873 | i = 0; | 865 | i = 0; |
| 874 | /* Walk through entries, checking offsets. */ | 866 | /* Walk through entries, checking offsets. */ |
| 875 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 867 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 876 | check_entry_size_and_hooks, | 868 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
| 877 | newinfo, | 869 | entry0 + repl->size, repl->hook_entry, repl->underflow, |
| 878 | entry0, | 870 | repl->valid_hooks); |
| 879 | entry0 + size, | 871 | if (ret != 0) |
| 880 | hook_entries, underflows, valid_hooks, &i); | 872 | return ret; |
| 881 | if (ret != 0) | 873 | ++i; |
| 882 | return ret; | 874 | } |
| 883 | 875 | ||
| 884 | if (i != number) { | 876 | if (i != repl->num_entries) { |
| 885 | duprintf("translate_table: %u not %u entries\n", | 877 | duprintf("translate_table: %u not %u entries\n", |
| 886 | i, number); | 878 | i, repl->num_entries); |
| 887 | return -EINVAL; | 879 | return -EINVAL; |
| 888 | } | 880 | } |
| 889 | 881 | ||
| 890 | /* Check hooks all assigned */ | 882 | /* Check hooks all assigned */ |
| 891 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 883 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
| 892 | /* Only hooks which are valid */ | 884 | /* Only hooks which are valid */ |
| 893 | if (!(valid_hooks & (1 << i))) | 885 | if (!(repl->valid_hooks & (1 << i))) |
| 894 | continue; | 886 | continue; |
| 895 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 887 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
| 896 | duprintf("Invalid hook entry %u %u\n", | 888 | duprintf("Invalid hook entry %u %u\n", |
| 897 | i, hook_entries[i]); | 889 | i, repl->hook_entry[i]); |
| 898 | return -EINVAL; | 890 | return -EINVAL; |
| 899 | } | 891 | } |
| 900 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 892 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
| 901 | duprintf("Invalid underflow %u %u\n", | 893 | duprintf("Invalid underflow %u %u\n", |
| 902 | i, underflows[i]); | 894 | i, repl->underflow[i]); |
| 903 | return -EINVAL; | 895 | return -EINVAL; |
| 904 | } | 896 | } |
| 905 | } | 897 | } |
| 906 | 898 | ||
| 907 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | 899 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) |
| 908 | return -ELOOP; | 900 | return -ELOOP; |
| 909 | 901 | ||
| 910 | /* Finally, each sanity check must pass */ | 902 | /* Finally, each sanity check must pass */ |
| 911 | i = 0; | 903 | i = 0; |
| 912 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 904 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 913 | find_check_entry, net, name, size, &i); | 905 | ret = find_check_entry(iter, net, repl->name, repl->size); |
| 906 | if (ret != 0) | ||
| 907 | break; | ||
| 908 | ++i; | ||
| 909 | } | ||
| 914 | 910 | ||
| 915 | if (ret != 0) { | 911 | if (ret != 0) { |
| 916 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 912 | xt_entry_foreach(iter, entry0, newinfo->size) { |
| 917 | cleanup_entry, net, &i); | 913 | if (i-- == 0) |
| 914 | break; | ||
| 915 | cleanup_entry(iter, net); | ||
| 916 | } | ||
| 918 | return ret; | 917 | return ret; |
| 919 | } | 918 | } |
| 920 | 919 | ||
| @@ -927,33 +926,11 @@ translate_table(struct net *net, | |||
| 927 | return ret; | 926 | return ret; |
| 928 | } | 927 | } |
| 929 | 928 | ||
| 930 | /* Gets counters. */ | ||
| 931 | static inline int | ||
| 932 | add_entry_to_counter(const struct ip6t_entry *e, | ||
| 933 | struct xt_counters total[], | ||
| 934 | unsigned int *i) | ||
| 935 | { | ||
| 936 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
| 937 | |||
| 938 | (*i)++; | ||
| 939 | return 0; | ||
| 940 | } | ||
| 941 | |||
| 942 | static inline int | ||
| 943 | set_entry_to_counter(const struct ip6t_entry *e, | ||
| 944 | struct ip6t_counters total[], | ||
| 945 | unsigned int *i) | ||
| 946 | { | ||
| 947 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
| 948 | |||
| 949 | (*i)++; | ||
| 950 | return 0; | ||
| 951 | } | ||
| 952 | |||
| 953 | static void | 929 | static void |
| 954 | get_counters(const struct xt_table_info *t, | 930 | get_counters(const struct xt_table_info *t, |
| 955 | struct xt_counters counters[]) | 931 | struct xt_counters counters[]) |
| 956 | { | 932 | { |
| 933 | struct ip6t_entry *iter; | ||
| 957 | unsigned int cpu; | 934 | unsigned int cpu; |
| 958 | unsigned int i; | 935 | unsigned int i; |
| 959 | unsigned int curcpu; | 936 | unsigned int curcpu; |
| @@ -969,22 +946,22 @@ get_counters(const struct xt_table_info *t, | |||
| 969 | curcpu = smp_processor_id(); | 946 | curcpu = smp_processor_id(); |
| 970 | 947 | ||
| 971 | i = 0; | 948 | i = 0; |
| 972 | IP6T_ENTRY_ITERATE(t->entries[curcpu], | 949 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
| 973 | t->size, | 950 | SET_COUNTER(counters[i], iter->counters.bcnt, |
| 974 | set_entry_to_counter, | 951 | iter->counters.pcnt); |
| 975 | counters, | 952 | ++i; |
| 976 | &i); | 953 | } |
| 977 | 954 | ||
| 978 | for_each_possible_cpu(cpu) { | 955 | for_each_possible_cpu(cpu) { |
| 979 | if (cpu == curcpu) | 956 | if (cpu == curcpu) |
| 980 | continue; | 957 | continue; |
| 981 | i = 0; | 958 | i = 0; |
| 982 | xt_info_wrlock(cpu); | 959 | xt_info_wrlock(cpu); |
| 983 | IP6T_ENTRY_ITERATE(t->entries[cpu], | 960 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
| 984 | t->size, | 961 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
| 985 | add_entry_to_counter, | 962 | iter->counters.pcnt); |
| 986 | counters, | 963 | ++i; |
| 987 | &i); | 964 | } |
| 988 | xt_info_wrunlock(cpu); | 965 | xt_info_wrunlock(cpu); |
| 989 | } | 966 | } |
| 990 | local_bh_enable(); | 967 | local_bh_enable(); |
| @@ -1103,24 +1080,19 @@ static int compat_standard_to_user(void __user *dst, const void *src) | |||
| 1103 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; | 1080 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; |
| 1104 | } | 1081 | } |
| 1105 | 1082 | ||
| 1106 | static inline int | ||
| 1107 | compat_calc_match(const struct ip6t_entry_match *m, int *size) | ||
| 1108 | { | ||
| 1109 | *size += xt_compat_match_offset(m->u.kernel.match); | ||
| 1110 | return 0; | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | static int compat_calc_entry(const struct ip6t_entry *e, | 1083 | static int compat_calc_entry(const struct ip6t_entry *e, |
| 1114 | const struct xt_table_info *info, | 1084 | const struct xt_table_info *info, |
| 1115 | const void *base, struct xt_table_info *newinfo) | 1085 | const void *base, struct xt_table_info *newinfo) |
| 1116 | { | 1086 | { |
| 1087 | const struct xt_entry_match *ematch; | ||
| 1117 | const struct ip6t_entry_target *t; | 1088 | const struct ip6t_entry_target *t; |
| 1118 | unsigned int entry_offset; | 1089 | unsigned int entry_offset; |
| 1119 | int off, i, ret; | 1090 | int off, i, ret; |
| 1120 | 1091 | ||
| 1121 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1092 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
| 1122 | entry_offset = (void *)e - base; | 1093 | entry_offset = (void *)e - base; |
| 1123 | IP6T_MATCH_ITERATE(e, compat_calc_match, &off); | 1094 | xt_ematch_foreach(ematch, e) |
| 1095 | off += xt_compat_match_offset(ematch->u.kernel.match); | ||
| 1124 | t = ip6t_get_target_c(e); | 1096 | t = ip6t_get_target_c(e); |
| 1125 | off += xt_compat_target_offset(t->u.kernel.target); | 1097 | off += xt_compat_target_offset(t->u.kernel.target); |
| 1126 | newinfo->size -= off; | 1098 | newinfo->size -= off; |
| @@ -1142,7 +1114,9 @@ static int compat_calc_entry(const struct ip6t_entry *e, | |||
| 1142 | static int compat_table_info(const struct xt_table_info *info, | 1114 | static int compat_table_info(const struct xt_table_info *info, |
| 1143 | struct xt_table_info *newinfo) | 1115 | struct xt_table_info *newinfo) |
| 1144 | { | 1116 | { |
| 1117 | struct ip6t_entry *iter; | ||
| 1145 | void *loc_cpu_entry; | 1118 | void *loc_cpu_entry; |
| 1119 | int ret; | ||
| 1146 | 1120 | ||
| 1147 | if (!newinfo || !info) | 1121 | if (!newinfo || !info) |
| 1148 | return -EINVAL; | 1122 | return -EINVAL; |
| @@ -1151,9 +1125,12 @@ static int compat_table_info(const struct xt_table_info *info, | |||
| 1151 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 1125 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
| 1152 | newinfo->initial_entries = 0; | 1126 | newinfo->initial_entries = 0; |
| 1153 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 1127 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
| 1154 | return IP6T_ENTRY_ITERATE(loc_cpu_entry, info->size, | 1128 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
| 1155 | compat_calc_entry, info, loc_cpu_entry, | 1129 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
| 1156 | newinfo); | 1130 | if (ret != 0) |
| 1131 | return ret; | ||
| 1132 | } | ||
| 1133 | return 0; | ||
| 1157 | } | 1134 | } |
| 1158 | #endif | 1135 | #endif |
| 1159 | 1136 | ||
| @@ -1267,6 +1244,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
| 1267 | struct xt_table_info *oldinfo; | 1244 | struct xt_table_info *oldinfo; |
| 1268 | struct xt_counters *counters; | 1245 | struct xt_counters *counters; |
| 1269 | const void *loc_cpu_old_entry; | 1246 | const void *loc_cpu_old_entry; |
| 1247 | struct ip6t_entry *iter; | ||
| 1270 | 1248 | ||
| 1271 | ret = 0; | 1249 | ret = 0; |
| 1272 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), | 1250 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), |
| @@ -1310,8 +1288,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
| 1310 | 1288 | ||
| 1311 | /* Decrease module usage counts and free resource */ | 1289 | /* Decrease module usage counts and free resource */ |
| 1312 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1290 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
| 1313 | IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1291 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
| 1314 | net, NULL); | 1292 | cleanup_entry(iter, net); |
| 1293 | |||
| 1315 | xt_free_table_info(oldinfo); | 1294 | xt_free_table_info(oldinfo); |
| 1316 | if (copy_to_user(counters_ptr, counters, | 1295 | if (copy_to_user(counters_ptr, counters, |
| 1317 | sizeof(struct xt_counters) * num_counters) != 0) | 1296 | sizeof(struct xt_counters) * num_counters) != 0) |
| @@ -1336,6 +1315,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
| 1336 | struct ip6t_replace tmp; | 1315 | struct ip6t_replace tmp; |
| 1337 | struct xt_table_info *newinfo; | 1316 | struct xt_table_info *newinfo; |
| 1338 | void *loc_cpu_entry; | 1317 | void *loc_cpu_entry; |
| 1318 | struct ip6t_entry *iter; | ||
| 1339 | 1319 | ||
| 1340 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1320 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
| 1341 | return -EFAULT; | 1321 | return -EFAULT; |
| @@ -1356,9 +1336,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
| 1356 | goto free_newinfo; | 1336 | goto free_newinfo; |
| 1357 | } | 1337 | } |
| 1358 | 1338 | ||
| 1359 | ret = translate_table(net, tmp.name, tmp.valid_hooks, | 1339 | ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); |
| 1360 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
| 1361 | tmp.hook_entry, tmp.underflow); | ||
| 1362 | if (ret != 0) | 1340 | if (ret != 0) |
| 1363 | goto free_newinfo; | 1341 | goto free_newinfo; |
| 1364 | 1342 | ||
| @@ -1371,25 +1349,13 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
| 1371 | return 0; | 1349 | return 0; |
| 1372 | 1350 | ||
| 1373 | free_newinfo_untrans: | 1351 | free_newinfo_untrans: |
| 1374 | IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1352 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
| 1353 | cleanup_entry(iter, net); | ||
| 1375 | free_newinfo: | 1354 | free_newinfo: |
| 1376 | xt_free_table_info(newinfo); | 1355 | xt_free_table_info(newinfo); |
| 1377 | return ret; | 1356 | return ret; |
| 1378 | } | 1357 | } |
| 1379 | 1358 | ||
| 1380 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
| 1381 | * and everything is OK. */ | ||
| 1382 | static int | ||
| 1383 | add_counter_to_entry(struct ip6t_entry *e, | ||
| 1384 | const struct xt_counters addme[], | ||
| 1385 | unsigned int *i) | ||
| 1386 | { | ||
| 1387 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
| 1388 | |||
| 1389 | (*i)++; | ||
| 1390 | return 0; | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | static int | 1359 | static int |
| 1394 | do_add_counters(struct net *net, const void __user *user, unsigned int len, | 1360 | do_add_counters(struct net *net, const void __user *user, unsigned int len, |
| 1395 | int compat) | 1361 | int compat) |
| @@ -1405,6 +1371,7 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
| 1405 | const struct xt_table_info *private; | 1371 | const struct xt_table_info *private; |
| 1406 | int ret = 0; | 1372 | int ret = 0; |
| 1407 | const void *loc_cpu_entry; | 1373 | const void *loc_cpu_entry; |
| 1374 | struct ip6t_entry *iter; | ||
| 1408 | #ifdef CONFIG_COMPAT | 1375 | #ifdef CONFIG_COMPAT |
| 1409 | struct compat_xt_counters_info compat_tmp; | 1376 | struct compat_xt_counters_info compat_tmp; |
| 1410 | 1377 | ||
| @@ -1463,11 +1430,10 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
| 1463 | curcpu = smp_processor_id(); | 1430 | curcpu = smp_processor_id(); |
| 1464 | xt_info_wrlock(curcpu); | 1431 | xt_info_wrlock(curcpu); |
| 1465 | loc_cpu_entry = private->entries[curcpu]; | 1432 | loc_cpu_entry = private->entries[curcpu]; |
| 1466 | IP6T_ENTRY_ITERATE(loc_cpu_entry, | 1433 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
| 1467 | private->size, | 1434 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
| 1468 | add_counter_to_entry, | 1435 | ++i; |
| 1469 | paddc, | 1436 | } |
| 1470 | &i); | ||
| 1471 | xt_info_wrunlock(curcpu); | 1437 | xt_info_wrunlock(curcpu); |
| 1472 | 1438 | ||
| 1473 | unlock_up_free: | 1439 | unlock_up_free: |
| @@ -1496,45 +1462,40 @@ struct compat_ip6t_replace { | |||
| 1496 | static int | 1462 | static int |
| 1497 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | 1463 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, |
| 1498 | unsigned int *size, struct xt_counters *counters, | 1464 | unsigned int *size, struct xt_counters *counters, |
| 1499 | unsigned int *i) | 1465 | unsigned int i) |
| 1500 | { | 1466 | { |
| 1501 | struct ip6t_entry_target *t; | 1467 | struct ip6t_entry_target *t; |
| 1502 | struct compat_ip6t_entry __user *ce; | 1468 | struct compat_ip6t_entry __user *ce; |
| 1503 | u_int16_t target_offset, next_offset; | 1469 | u_int16_t target_offset, next_offset; |
| 1504 | compat_uint_t origsize; | 1470 | compat_uint_t origsize; |
| 1505 | int ret; | 1471 | const struct xt_entry_match *ematch; |
| 1472 | int ret = 0; | ||
| 1506 | 1473 | ||
| 1507 | ret = -EFAULT; | ||
| 1508 | origsize = *size; | 1474 | origsize = *size; |
| 1509 | ce = (struct compat_ip6t_entry __user *)*dstptr; | 1475 | ce = (struct compat_ip6t_entry __user *)*dstptr; |
| 1510 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry))) | 1476 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || |
| 1511 | goto out; | 1477 | copy_to_user(&ce->counters, &counters[i], |
| 1512 | 1478 | sizeof(counters[i])) != 0) | |
| 1513 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1479 | return -EFAULT; |
| 1514 | goto out; | ||
| 1515 | 1480 | ||
| 1516 | *dstptr += sizeof(struct compat_ip6t_entry); | 1481 | *dstptr += sizeof(struct compat_ip6t_entry); |
| 1517 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1482 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
| 1518 | 1483 | ||
| 1519 | ret = IP6T_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); | 1484 | xt_ematch_foreach(ematch, e) { |
| 1485 | ret = xt_compat_match_to_user(ematch, dstptr, size); | ||
| 1486 | if (ret != 0) | ||
| 1487 | return ret; | ||
| 1488 | } | ||
| 1520 | target_offset = e->target_offset - (origsize - *size); | 1489 | target_offset = e->target_offset - (origsize - *size); |
| 1521 | if (ret) | ||
| 1522 | goto out; | ||
| 1523 | t = ip6t_get_target(e); | 1490 | t = ip6t_get_target(e); |
| 1524 | ret = xt_compat_target_to_user(t, dstptr, size); | 1491 | ret = xt_compat_target_to_user(t, dstptr, size); |
| 1525 | if (ret) | 1492 | if (ret) |
| 1526 | goto out; | 1493 | return ret; |
| 1527 | ret = -EFAULT; | ||
| 1528 | next_offset = e->next_offset - (origsize - *size); | 1494 | next_offset = e->next_offset - (origsize - *size); |
| 1529 | if (put_user(target_offset, &ce->target_offset)) | 1495 | if (put_user(target_offset, &ce->target_offset) != 0 || |
| 1530 | goto out; | 1496 | put_user(next_offset, &ce->next_offset) != 0) |
| 1531 | if (put_user(next_offset, &ce->next_offset)) | 1497 | return -EFAULT; |
| 1532 | goto out; | ||
| 1533 | |||
| 1534 | (*i)++; | ||
| 1535 | return 0; | 1498 | return 0; |
| 1536 | out: | ||
| 1537 | return ret; | ||
| 1538 | } | 1499 | } |
| 1539 | 1500 | ||
| 1540 | static int | 1501 | static int |
| @@ -1542,7 +1503,7 @@ compat_find_calc_match(struct ip6t_entry_match *m, | |||
| 1542 | const char *name, | 1503 | const char *name, |
| 1543 | const struct ip6t_ip6 *ipv6, | 1504 | const struct ip6t_ip6 *ipv6, |
| 1544 | unsigned int hookmask, | 1505 | unsigned int hookmask, |
| 1545 | int *size, unsigned int *i) | 1506 | int *size) |
| 1546 | { | 1507 | { |
| 1547 | struct xt_match *match; | 1508 | struct xt_match *match; |
| 1548 | 1509 | ||
| @@ -1556,34 +1517,19 @@ compat_find_calc_match(struct ip6t_entry_match *m, | |||
| 1556 | } | 1517 | } |
| 1557 | m->u.kernel.match = match; | 1518 | m->u.kernel.match = match; |
| 1558 | *size += xt_compat_match_offset(match); | 1519 | *size += xt_compat_match_offset(match); |
| 1559 | |||
| 1560 | (*i)++; | ||
| 1561 | return 0; | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | static int | ||
| 1565 | compat_release_match(struct ip6t_entry_match *m, unsigned int *i) | ||
| 1566 | { | ||
| 1567 | if (i && (*i)-- == 0) | ||
| 1568 | return 1; | ||
| 1569 | |||
| 1570 | module_put(m->u.kernel.match->me); | ||
| 1571 | return 0; | 1520 | return 0; |
| 1572 | } | 1521 | } |
| 1573 | 1522 | ||
| 1574 | static int | 1523 | static void compat_release_entry(struct compat_ip6t_entry *e) |
| 1575 | compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i) | ||
| 1576 | { | 1524 | { |
| 1577 | struct ip6t_entry_target *t; | 1525 | struct ip6t_entry_target *t; |
| 1578 | 1526 | struct xt_entry_match *ematch; | |
| 1579 | if (i && (*i)-- == 0) | ||
| 1580 | return 1; | ||
| 1581 | 1527 | ||
| 1582 | /* Cleanup all matches */ | 1528 | /* Cleanup all matches */ |
| 1583 | COMPAT_IP6T_MATCH_ITERATE(e, compat_release_match, NULL); | 1529 | xt_ematch_foreach(ematch, e) |
| 1530 | module_put(ematch->u.kernel.match->me); | ||
| 1584 | t = compat_ip6t_get_target(e); | 1531 | t = compat_ip6t_get_target(e); |
| 1585 | module_put(t->u.kernel.target->me); | 1532 | module_put(t->u.kernel.target->me); |
| 1586 | return 0; | ||
| 1587 | } | 1533 | } |
| 1588 | 1534 | ||
| 1589 | static int | 1535 | static int |
| @@ -1594,9 +1540,9 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
| 1594 | const unsigned char *limit, | 1540 | const unsigned char *limit, |
| 1595 | const unsigned int *hook_entries, | 1541 | const unsigned int *hook_entries, |
| 1596 | const unsigned int *underflows, | 1542 | const unsigned int *underflows, |
| 1597 | unsigned int *i, | ||
| 1598 | const char *name) | 1543 | const char *name) |
| 1599 | { | 1544 | { |
| 1545 | struct xt_entry_match *ematch; | ||
| 1600 | struct ip6t_entry_target *t; | 1546 | struct ip6t_entry_target *t; |
| 1601 | struct xt_target *target; | 1547 | struct xt_target *target; |
| 1602 | unsigned int entry_offset; | 1548 | unsigned int entry_offset; |
| @@ -1625,10 +1571,13 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
| 1625 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1571 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
| 1626 | entry_offset = (void *)e - (void *)base; | 1572 | entry_offset = (void *)e - (void *)base; |
| 1627 | j = 0; | 1573 | j = 0; |
| 1628 | ret = COMPAT_IP6T_MATCH_ITERATE(e, compat_find_calc_match, name, | 1574 | xt_ematch_foreach(ematch, e) { |
| 1629 | &e->ipv6, e->comefrom, &off, &j); | 1575 | ret = compat_find_calc_match(ematch, name, |
| 1630 | if (ret != 0) | 1576 | &e->ipv6, e->comefrom, &off); |
| 1631 | goto release_matches; | 1577 | if (ret != 0) |
| 1578 | goto release_matches; | ||
| 1579 | ++j; | ||
| 1580 | } | ||
| 1632 | 1581 | ||
| 1633 | t = compat_ip6t_get_target(e); | 1582 | t = compat_ip6t_get_target(e); |
| 1634 | target = try_then_request_module(xt_find_target(AF_INET6, | 1583 | target = try_then_request_module(xt_find_target(AF_INET6, |
| @@ -1660,14 +1609,16 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
| 1660 | /* Clear counters and comefrom */ | 1609 | /* Clear counters and comefrom */ |
| 1661 | memset(&e->counters, 0, sizeof(e->counters)); | 1610 | memset(&e->counters, 0, sizeof(e->counters)); |
| 1662 | e->comefrom = 0; | 1611 | e->comefrom = 0; |
| 1663 | |||
| 1664 | (*i)++; | ||
| 1665 | return 0; | 1612 | return 0; |
| 1666 | 1613 | ||
| 1667 | out: | 1614 | out: |
| 1668 | module_put(t->u.kernel.target->me); | 1615 | module_put(t->u.kernel.target->me); |
| 1669 | release_matches: | 1616 | release_matches: |
| 1670 | IP6T_MATCH_ITERATE(e, compat_release_match, &j); | 1617 | xt_ematch_foreach(ematch, e) { |
| 1618 | if (j-- == 0) | ||
| 1619 | break; | ||
| 1620 | module_put(ematch->u.kernel.match->me); | ||
| 1621 | } | ||
| 1671 | return ret; | 1622 | return ret; |
| 1672 | } | 1623 | } |
| 1673 | 1624 | ||
| @@ -1681,6 +1632,7 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
| 1681 | struct ip6t_entry *de; | 1632 | struct ip6t_entry *de; |
| 1682 | unsigned int origsize; | 1633 | unsigned int origsize; |
| 1683 | int ret, h; | 1634 | int ret, h; |
| 1635 | struct xt_entry_match *ematch; | ||
| 1684 | 1636 | ||
| 1685 | ret = 0; | 1637 | ret = 0; |
| 1686 | origsize = *size; | 1638 | origsize = *size; |
| @@ -1691,10 +1643,11 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
| 1691 | *dstptr += sizeof(struct ip6t_entry); | 1643 | *dstptr += sizeof(struct ip6t_entry); |
| 1692 | *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1644 | *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
| 1693 | 1645 | ||
| 1694 | ret = COMPAT_IP6T_MATCH_ITERATE(e, xt_compat_match_from_user, | 1646 | xt_ematch_foreach(ematch, e) { |
| 1695 | dstptr, size); | 1647 | ret = xt_compat_match_from_user(ematch, dstptr, size); |
| 1696 | if (ret) | 1648 | if (ret != 0) |
| 1697 | return ret; | 1649 | return ret; |
| 1650 | } | ||
| 1698 | de->target_offset = e->target_offset - (origsize - *size); | 1651 | de->target_offset = e->target_offset - (origsize - *size); |
| 1699 | t = compat_ip6t_get_target(e); | 1652 | t = compat_ip6t_get_target(e); |
| 1700 | target = t->u.kernel.target; | 1653 | target = t->u.kernel.target; |
| @@ -1711,11 +1664,12 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
| 1711 | } | 1664 | } |
| 1712 | 1665 | ||
| 1713 | static int compat_check_entry(struct ip6t_entry *e, struct net *net, | 1666 | static int compat_check_entry(struct ip6t_entry *e, struct net *net, |
| 1714 | const char *name, unsigned int *i) | 1667 | const char *name) |
| 1715 | { | 1668 | { |
| 1716 | unsigned int j; | 1669 | unsigned int j; |
| 1717 | int ret; | 1670 | int ret = 0; |
| 1718 | struct xt_mtchk_param mtpar; | 1671 | struct xt_mtchk_param mtpar; |
| 1672 | struct xt_entry_match *ematch; | ||
| 1719 | 1673 | ||
| 1720 | j = 0; | 1674 | j = 0; |
| 1721 | mtpar.net = net; | 1675 | mtpar.net = net; |
| @@ -1723,19 +1677,24 @@ static int compat_check_entry(struct ip6t_entry *e, struct net *net, | |||
| 1723 | mtpar.entryinfo = &e->ipv6; | 1677 | mtpar.entryinfo = &e->ipv6; |
| 1724 | mtpar.hook_mask = e->comefrom; | 1678 | mtpar.hook_mask = e->comefrom; |
| 1725 | mtpar.family = NFPROTO_IPV6; | 1679 | mtpar.family = NFPROTO_IPV6; |
| 1726 | ret = IP6T_MATCH_ITERATE(e, check_match, &mtpar, &j); | 1680 | xt_ematch_foreach(ematch, e) { |
| 1727 | if (ret) | 1681 | ret = check_match(ematch, &mtpar); |
| 1728 | goto cleanup_matches; | 1682 | if (ret != 0) |
| 1683 | goto cleanup_matches; | ||
| 1684 | ++j; | ||
| 1685 | } | ||
| 1729 | 1686 | ||
| 1730 | ret = check_target(e, net, name); | 1687 | ret = check_target(e, net, name); |
| 1731 | if (ret) | 1688 | if (ret) |
| 1732 | goto cleanup_matches; | 1689 | goto cleanup_matches; |
| 1733 | |||
| 1734 | (*i)++; | ||
| 1735 | return 0; | 1690 | return 0; |
| 1736 | 1691 | ||
| 1737 | cleanup_matches: | 1692 | cleanup_matches: |
| 1738 | IP6T_MATCH_ITERATE(e, cleanup_match, net, &j); | 1693 | xt_ematch_foreach(ematch, e) { |
| 1694 | if (j-- == 0) | ||
| 1695 | break; | ||
| 1696 | cleanup_match(ematch, net); | ||
| 1697 | } | ||
| 1739 | return ret; | 1698 | return ret; |
| 1740 | } | 1699 | } |
| 1741 | 1700 | ||
| @@ -1753,8 +1712,10 @@ translate_compat_table(struct net *net, | |||
| 1753 | unsigned int i, j; | 1712 | unsigned int i, j; |
| 1754 | struct xt_table_info *newinfo, *info; | 1713 | struct xt_table_info *newinfo, *info; |
| 1755 | void *pos, *entry0, *entry1; | 1714 | void *pos, *entry0, *entry1; |
| 1715 | struct compat_ip6t_entry *iter0; | ||
| 1716 | struct ip6t_entry *iter1; | ||
| 1756 | unsigned int size; | 1717 | unsigned int size; |
| 1757 | int ret; | 1718 | int ret = 0; |
| 1758 | 1719 | ||
| 1759 | info = *pinfo; | 1720 | info = *pinfo; |
| 1760 | entry0 = *pentry0; | 1721 | entry0 = *pentry0; |
| @@ -1771,13 +1732,14 @@ translate_compat_table(struct net *net, | |||
| 1771 | j = 0; | 1732 | j = 0; |
| 1772 | xt_compat_lock(AF_INET6); | 1733 | xt_compat_lock(AF_INET6); |
| 1773 | /* Walk through entries, checking offsets. */ | 1734 | /* Walk through entries, checking offsets. */ |
| 1774 | ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, | 1735 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1775 | check_compat_entry_size_and_hooks, | 1736 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
| 1776 | info, &size, entry0, | 1737 | entry0, entry0 + total_size, hook_entries, underflows, |
| 1777 | entry0 + total_size, | 1738 | name); |
| 1778 | hook_entries, underflows, &j, name); | 1739 | if (ret != 0) |
| 1779 | if (ret != 0) | 1740 | goto out_unlock; |
| 1780 | goto out_unlock; | 1741 | ++j; |
| 1742 | } | ||
| 1781 | 1743 | ||
| 1782 | ret = -EINVAL; | 1744 | ret = -EINVAL; |
| 1783 | if (j != number) { | 1745 | if (j != number) { |
| @@ -1816,9 +1778,12 @@ translate_compat_table(struct net *net, | |||
| 1816 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1778 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
| 1817 | pos = entry1; | 1779 | pos = entry1; |
| 1818 | size = total_size; | 1780 | size = total_size; |
| 1819 | ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, | 1781 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1820 | compat_copy_entry_from_user, | 1782 | ret = compat_copy_entry_from_user(iter0, &pos, |
| 1821 | &pos, &size, name, newinfo, entry1); | 1783 | &size, name, newinfo, entry1); |
| 1784 | if (ret != 0) | ||
| 1785 | break; | ||
| 1786 | } | ||
| 1822 | xt_compat_flush_offsets(AF_INET6); | 1787 | xt_compat_flush_offsets(AF_INET6); |
| 1823 | xt_compat_unlock(AF_INET6); | 1788 | xt_compat_unlock(AF_INET6); |
| 1824 | if (ret) | 1789 | if (ret) |
| @@ -1829,13 +1794,32 @@ translate_compat_table(struct net *net, | |||
| 1829 | goto free_newinfo; | 1794 | goto free_newinfo; |
| 1830 | 1795 | ||
| 1831 | i = 0; | 1796 | i = 0; |
| 1832 | ret = IP6T_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1797 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
| 1833 | net, name, &i); | 1798 | ret = compat_check_entry(iter1, net, name); |
| 1799 | if (ret != 0) | ||
| 1800 | break; | ||
| 1801 | ++i; | ||
| 1802 | } | ||
| 1834 | if (ret) { | 1803 | if (ret) { |
| 1804 | /* | ||
| 1805 | * The first i matches need cleanup_entry (calls ->destroy) | ||
| 1806 | * because they had called ->check already. The other j-i | ||
| 1807 | * entries need only release. | ||
| 1808 | */ | ||
| 1809 | int skip = i; | ||
| 1835 | j -= i; | 1810 | j -= i; |
| 1836 | COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1811 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
| 1837 | compat_release_entry, &j); | 1812 | if (skip-- > 0) |
| 1838 | IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, net, &i); | 1813 | continue; |
| 1814 | if (j-- == 0) | ||
| 1815 | break; | ||
| 1816 | compat_release_entry(iter0); | ||
| 1817 | } | ||
| 1818 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
| 1819 | if (i-- == 0) | ||
| 1820 | break; | ||
| 1821 | cleanup_entry(iter1, net); | ||
| 1822 | } | ||
| 1839 | xt_free_table_info(newinfo); | 1823 | xt_free_table_info(newinfo); |
| 1840 | return ret; | 1824 | return ret; |
| 1841 | } | 1825 | } |
| @@ -1853,7 +1837,11 @@ translate_compat_table(struct net *net, | |||
| 1853 | free_newinfo: | 1837 | free_newinfo: |
| 1854 | xt_free_table_info(newinfo); | 1838 | xt_free_table_info(newinfo); |
| 1855 | out: | 1839 | out: |
| 1856 | COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1840 | xt_entry_foreach(iter0, entry0, total_size) { |
| 1841 | if (j-- == 0) | ||
| 1842 | break; | ||
| 1843 | compat_release_entry(iter0); | ||
| 1844 | } | ||
| 1857 | return ret; | 1845 | return ret; |
| 1858 | out_unlock: | 1846 | out_unlock: |
| 1859 | xt_compat_flush_offsets(AF_INET6); | 1847 | xt_compat_flush_offsets(AF_INET6); |
| @@ -1868,6 +1856,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1868 | struct compat_ip6t_replace tmp; | 1856 | struct compat_ip6t_replace tmp; |
| 1869 | struct xt_table_info *newinfo; | 1857 | struct xt_table_info *newinfo; |
| 1870 | void *loc_cpu_entry; | 1858 | void *loc_cpu_entry; |
| 1859 | struct ip6t_entry *iter; | ||
| 1871 | 1860 | ||
| 1872 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1861 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
| 1873 | return -EFAULT; | 1862 | return -EFAULT; |
| @@ -1906,7 +1895,8 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
| 1906 | return 0; | 1895 | return 0; |
| 1907 | 1896 | ||
| 1908 | free_newinfo_untrans: | 1897 | free_newinfo_untrans: |
| 1909 | IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL); | 1898 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
| 1899 | cleanup_entry(iter, net); | ||
| 1910 | free_newinfo: | 1900 | free_newinfo: |
| 1911 | xt_free_table_info(newinfo); | 1901 | xt_free_table_info(newinfo); |
| 1912 | return ret; | 1902 | return ret; |
| @@ -1955,6 +1945,7 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
| 1955 | int ret = 0; | 1945 | int ret = 0; |
| 1956 | const void *loc_cpu_entry; | 1946 | const void *loc_cpu_entry; |
| 1957 | unsigned int i = 0; | 1947 | unsigned int i = 0; |
| 1948 | struct ip6t_entry *iter; | ||
| 1958 | 1949 | ||
| 1959 | counters = alloc_counters(table); | 1950 | counters = alloc_counters(table); |
| 1960 | if (IS_ERR(counters)) | 1951 | if (IS_ERR(counters)) |
| @@ -1967,9 +1958,12 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
| 1967 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1958 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| 1968 | pos = userptr; | 1959 | pos = userptr; |
| 1969 | size = total_size; | 1960 | size = total_size; |
| 1970 | ret = IP6T_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1961 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
| 1971 | compat_copy_entry_to_user, | 1962 | ret = compat_copy_entry_to_user(iter, &pos, |
| 1972 | &pos, &size, counters, &i); | 1963 | &size, counters, i++); |
| 1964 | if (ret != 0) | ||
| 1965 | break; | ||
| 1966 | } | ||
| 1973 | 1967 | ||
| 1974 | vfree(counters); | 1968 | vfree(counters); |
| 1975 | return ret; | 1969 | return ret; |
| @@ -2143,11 +2137,7 @@ struct xt_table *ip6t_register_table(struct net *net, | |||
| 2143 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 2137 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
| 2144 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 2138 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
| 2145 | 2139 | ||
| 2146 | ret = translate_table(net, table->name, table->valid_hooks, | 2140 | ret = translate_table(net, newinfo, loc_cpu_entry, repl); |
| 2147 | newinfo, loc_cpu_entry, repl->size, | ||
| 2148 | repl->num_entries, | ||
| 2149 | repl->hook_entry, | ||
| 2150 | repl->underflow); | ||
| 2151 | if (ret != 0) | 2141 | if (ret != 0) |
| 2152 | goto out_free; | 2142 | goto out_free; |
| 2153 | 2143 | ||
| @@ -2169,12 +2159,14 @@ void ip6t_unregister_table(struct net *net, struct xt_table *table) | |||
| 2169 | struct xt_table_info *private; | 2159 | struct xt_table_info *private; |
| 2170 | void *loc_cpu_entry; | 2160 | void *loc_cpu_entry; |
| 2171 | struct module *table_owner = table->me; | 2161 | struct module *table_owner = table->me; |
| 2162 | struct ip6t_entry *iter; | ||
| 2172 | 2163 | ||
| 2173 | private = xt_unregister_table(table); | 2164 | private = xt_unregister_table(table); |
| 2174 | 2165 | ||
| 2175 | /* Decrease module usage counts and free resources */ | 2166 | /* Decrease module usage counts and free resources */ |
| 2176 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 2167 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| 2177 | IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, net, NULL); | 2168 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
| 2169 | cleanup_entry(iter, net); | ||
| 2178 | if (private->number > private->initial_entries) | 2170 | if (private->number > private->initial_entries) |
| 2179 | module_put(table_owner); | 2171 | module_put(table_owner); |
| 2180 | xt_free_table_info(private); | 2172 | xt_free_table_info(private); |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index ad1fcda6898b..f1171b744650 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
| @@ -469,7 +469,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
| 469 | 469 | ||
| 470 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ | 470 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ |
| 471 | fp = skb_shinfo(head)->frag_list; | 471 | fp = skb_shinfo(head)->frag_list; |
| 472 | if (NFCT_FRAG6_CB(fp)->orig == NULL) | 472 | if (fp && NFCT_FRAG6_CB(fp)->orig == NULL) |
| 473 | /* at above code, head skb is divided into two skbs. */ | 473 | /* at above code, head skb is divided into two skbs. */ |
| 474 | fp = fp->next; | 474 | fp = fp->next; |
| 475 | 475 | ||
| @@ -595,12 +595,6 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |||
| 595 | hdr = ipv6_hdr(clone); | 595 | hdr = ipv6_hdr(clone); |
| 596 | fhdr = (struct frag_hdr *)skb_transport_header(clone); | 596 | fhdr = (struct frag_hdr *)skb_transport_header(clone); |
| 597 | 597 | ||
| 598 | if (!(fhdr->frag_off & htons(0xFFF9))) { | ||
| 599 | pr_debug("Invalid fragment offset\n"); | ||
| 600 | /* It is not a fragmented frame */ | ||
| 601 | goto ret_orig; | ||
| 602 | } | ||
| 603 | |||
| 604 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) | 598 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) |
| 605 | nf_ct_frag6_evictor(); | 599 | nf_ct_frag6_evictor(); |
| 606 | 600 | ||
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 6f21b4377dbb..0e357ac9a2a8 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c | |||
| @@ -239,6 +239,7 @@ static bool tcpmss_tg4_check(const struct xt_tgchk_param *par) | |||
| 239 | { | 239 | { |
| 240 | const struct xt_tcpmss_info *info = par->targinfo; | 240 | const struct xt_tcpmss_info *info = par->targinfo; |
| 241 | const struct ipt_entry *e = par->entryinfo; | 241 | const struct ipt_entry *e = par->entryinfo; |
| 242 | const struct xt_entry_match *ematch; | ||
| 242 | 243 | ||
| 243 | if (info->mss == XT_TCPMSS_CLAMP_PMTU && | 244 | if (info->mss == XT_TCPMSS_CLAMP_PMTU && |
| 244 | (par->hook_mask & ~((1 << NF_INET_FORWARD) | | 245 | (par->hook_mask & ~((1 << NF_INET_FORWARD) | |
| @@ -248,8 +249,9 @@ static bool tcpmss_tg4_check(const struct xt_tgchk_param *par) | |||
| 248 | "FORWARD, OUTPUT and POSTROUTING hooks\n"); | 249 | "FORWARD, OUTPUT and POSTROUTING hooks\n"); |
| 249 | return false; | 250 | return false; |
| 250 | } | 251 | } |
| 251 | if (IPT_MATCH_ITERATE(e, find_syn_match)) | 252 | xt_ematch_foreach(ematch, e) |
| 252 | return true; | 253 | if (find_syn_match(ematch)) |
| 254 | return true; | ||
| 253 | printk("xt_TCPMSS: Only works on TCP SYN packets\n"); | 255 | printk("xt_TCPMSS: Only works on TCP SYN packets\n"); |
| 254 | return false; | 256 | return false; |
| 255 | } | 257 | } |
| @@ -259,6 +261,7 @@ static bool tcpmss_tg6_check(const struct xt_tgchk_param *par) | |||
| 259 | { | 261 | { |
| 260 | const struct xt_tcpmss_info *info = par->targinfo; | 262 | const struct xt_tcpmss_info *info = par->targinfo; |
| 261 | const struct ip6t_entry *e = par->entryinfo; | 263 | const struct ip6t_entry *e = par->entryinfo; |
| 264 | const struct xt_entry_match *ematch; | ||
| 262 | 265 | ||
| 263 | if (info->mss == XT_TCPMSS_CLAMP_PMTU && | 266 | if (info->mss == XT_TCPMSS_CLAMP_PMTU && |
| 264 | (par->hook_mask & ~((1 << NF_INET_FORWARD) | | 267 | (par->hook_mask & ~((1 << NF_INET_FORWARD) | |
| @@ -268,8 +271,9 @@ static bool tcpmss_tg6_check(const struct xt_tgchk_param *par) | |||
| 268 | "FORWARD, OUTPUT and POSTROUTING hooks\n"); | 271 | "FORWARD, OUTPUT and POSTROUTING hooks\n"); |
| 269 | return false; | 272 | return false; |
| 270 | } | 273 | } |
| 271 | if (IP6T_MATCH_ITERATE(e, find_syn_match)) | 274 | xt_ematch_foreach(ematch, e) |
| 272 | return true; | 275 | if (find_syn_match(ematch)) |
| 276 | return true; | ||
| 273 | printk("xt_TCPMSS: Only works on TCP SYN packets\n"); | 277 | printk("xt_TCPMSS: Only works on TCP SYN packets\n"); |
| 274 | return false; | 278 | return false; |
| 275 | } | 279 | } |
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 132cfaa84cdc..7073dbb8100c 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c | |||
| @@ -177,10 +177,10 @@ recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr, | |||
| 177 | 177 | ||
| 178 | static void recent_entry_update(struct recent_table *t, struct recent_entry *e) | 178 | static void recent_entry_update(struct recent_table *t, struct recent_entry *e) |
| 179 | { | 179 | { |
| 180 | e->index %= ip_pkt_list_tot; | ||
| 180 | e->stamps[e->index++] = jiffies; | 181 | e->stamps[e->index++] = jiffies; |
| 181 | if (e->index > e->nstamps) | 182 | if (e->index > e->nstamps) |
| 182 | e->nstamps = e->index; | 183 | e->nstamps = e->index; |
| 183 | e->index %= ip_pkt_list_tot; | ||
| 184 | list_move_tail(&e->lru_list, &t->lru_list); | 184 | list_move_tail(&e->lru_list, &t->lru_list); |
| 185 | } | 185 | } |
| 186 | 186 | ||
| @@ -267,7 +267,7 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |||
| 267 | for (i = 0; i < e->nstamps; i++) { | 267 | for (i = 0; i < e->nstamps; i++) { |
| 268 | if (info->seconds && time_after(time, e->stamps[i])) | 268 | if (info->seconds && time_after(time, e->stamps[i])) |
| 269 | continue; | 269 | continue; |
| 270 | if (++hits >= info->hit_count) { | 270 | if (info->hit_count && ++hits >= info->hit_count) { |
| 271 | ret = !ret; | 271 | ret = !ret; |
| 272 | break; | 272 | break; |
| 273 | } | 273 | } |
