diff options
author | Jan Engelhardt <jengelh@medozas.de> | 2010-02-24 12:33:43 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-02-24 12:33:43 -0500 |
commit | 0559518b5b99c591226460c0bbf8e6a570c518a8 (patch) | |
tree | da3dd25683636f80c4861150816c1cb1a643348a | |
parent | 72b2b1dd77e8feb0b7c0b26dee58f2a1e2c9828c (diff) |
netfilter: xtables: optimize call flow around xt_entry_foreach
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 180 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 183 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 179 |
3 files changed, 182 insertions, 360 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index f7338869fc4c..5fdedeb46218 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,7 +617,6 @@ 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 |
@@ -660,10 +650,10 @@ static int translate_table(const char *name, | |||
660 | /* Walk through entries, checking offsets. */ | 650 | /* Walk through entries, checking offsets. */ |
661 | xt_entry_foreach(iter, entry0, newinfo->size) { | 651 | xt_entry_foreach(iter, entry0, newinfo->size) { |
662 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, | 652 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
663 | entry0 + size, hook_entries, underflows, | 653 | entry0 + size, hook_entries, underflows, valid_hooks); |
664 | valid_hooks, &i); | ||
665 | if (ret != 0) | 654 | if (ret != 0) |
666 | break; | 655 | break; |
656 | ++i; | ||
667 | } | 657 | } |
668 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); | 658 | duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); |
669 | if (ret != 0) | 659 | if (ret != 0) |
@@ -700,15 +690,18 @@ static int translate_table(const char *name, | |||
700 | /* Finally, each sanity check must pass */ | 690 | /* Finally, each sanity check must pass */ |
701 | i = 0; | 691 | i = 0; |
702 | xt_entry_foreach(iter, entry0, newinfo->size) { | 692 | xt_entry_foreach(iter, entry0, newinfo->size) { |
703 | ret = find_check_entry(iter, name, size, &i); | 693 | ret = find_check_entry(iter, name, size); |
704 | if (ret != 0) | 694 | if (ret != 0) |
705 | break; | 695 | break; |
696 | ++i; | ||
706 | } | 697 | } |
707 | 698 | ||
708 | if (ret != 0) { | 699 | if (ret != 0) { |
709 | xt_entry_foreach(iter, entry0, newinfo->size) | 700 | xt_entry_foreach(iter, entry0, newinfo->size) { |
710 | if (cleanup_entry(iter, &i) != 0) | 701 | if (i-- == 0) |
711 | break; | 702 | break; |
703 | cleanup_entry(iter); | ||
704 | } | ||
712 | return ret; | 705 | return ret; |
713 | } | 706 | } |
714 | 707 | ||
@@ -721,27 +714,6 @@ static int translate_table(const char *name, | |||
721 | return ret; | 714 | return ret; |
722 | } | 715 | } |
723 | 716 | ||
724 | /* Gets counters. */ | ||
725 | static inline int add_entry_to_counter(const struct arpt_entry *e, | ||
726 | struct xt_counters total[], | ||
727 | unsigned int *i) | ||
728 | { | ||
729 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
730 | |||
731 | (*i)++; | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static inline int set_entry_to_counter(const struct arpt_entry *e, | ||
736 | struct xt_counters total[], | ||
737 | unsigned int *i) | ||
738 | { | ||
739 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
740 | |||
741 | (*i)++; | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static void get_counters(const struct xt_table_info *t, | 717 | static void get_counters(const struct xt_table_info *t, |
746 | struct xt_counters counters[]) | 718 | struct xt_counters counters[]) |
747 | { | 719 | { |
@@ -761,18 +733,22 @@ static void get_counters(const struct xt_table_info *t, | |||
761 | curcpu = smp_processor_id(); | 733 | curcpu = smp_processor_id(); |
762 | 734 | ||
763 | i = 0; | 735 | i = 0; |
764 | xt_entry_foreach(iter, t->entries[curcpu], t->size) | 736 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
765 | if (set_entry_to_counter(iter, counters, &i) != 0) | 737 | SET_COUNTER(counters[i], iter->counters.bcnt, |
766 | break; | 738 | iter->counters.pcnt); |
739 | ++i; | ||
740 | } | ||
767 | 741 | ||
768 | for_each_possible_cpu(cpu) { | 742 | for_each_possible_cpu(cpu) { |
769 | if (cpu == curcpu) | 743 | if (cpu == curcpu) |
770 | continue; | 744 | continue; |
771 | i = 0; | 745 | i = 0; |
772 | xt_info_wrlock(cpu); | 746 | xt_info_wrlock(cpu); |
773 | xt_entry_foreach(iter, t->entries[cpu], t->size) | 747 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
774 | if (add_entry_to_counter(iter, counters, &i) != 0) | 748 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
775 | break; | 749 | iter->counters.pcnt); |
750 | ++i; | ||
751 | } | ||
776 | xt_info_wrunlock(cpu); | 752 | xt_info_wrunlock(cpu); |
777 | } | 753 | } |
778 | local_bh_enable(); | 754 | local_bh_enable(); |
@@ -904,7 +880,7 @@ static int compat_table_info(const struct xt_table_info *info, | |||
904 | { | 880 | { |
905 | struct arpt_entry *iter; | 881 | struct arpt_entry *iter; |
906 | void *loc_cpu_entry; | 882 | void *loc_cpu_entry; |
907 | int ret = 0; | 883 | int ret; |
908 | 884 | ||
909 | if (!newinfo || !info) | 885 | if (!newinfo || !info) |
910 | return -EINVAL; | 886 | return -EINVAL; |
@@ -916,9 +892,9 @@ static int compat_table_info(const struct xt_table_info *info, | |||
916 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { | 892 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
917 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); | 893 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
918 | if (ret != 0) | 894 | if (ret != 0) |
919 | break; | 895 | return ret; |
920 | } | 896 | } |
921 | return ret; | 897 | return 0; |
922 | } | 898 | } |
923 | #endif | 899 | #endif |
924 | 900 | ||
@@ -1078,8 +1054,7 @@ static int __do_replace(struct net *net, const char *name, | |||
1078 | /* Decrease module usage counts and free resource */ | 1054 | /* Decrease module usage counts and free resource */ |
1079 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1055 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
1080 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) | 1056 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
1081 | if (cleanup_entry(iter, NULL) != 0) | 1057 | cleanup_entry(iter); |
1082 | break; | ||
1083 | 1058 | ||
1084 | xt_free_table_info(oldinfo); | 1059 | xt_free_table_info(oldinfo); |
1085 | if (copy_to_user(counters_ptr, counters, | 1060 | if (copy_to_user(counters_ptr, counters, |
@@ -1142,26 +1117,12 @@ static int do_replace(struct net *net, const void __user *user, | |||
1142 | 1117 | ||
1143 | free_newinfo_untrans: | 1118 | free_newinfo_untrans: |
1144 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) | 1119 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1145 | if (cleanup_entry(iter, NULL) != 0) | 1120 | cleanup_entry(iter); |
1146 | break; | ||
1147 | free_newinfo: | 1121 | free_newinfo: |
1148 | xt_free_table_info(newinfo); | 1122 | xt_free_table_info(newinfo); |
1149 | return ret; | 1123 | return ret; |
1150 | } | 1124 | } |
1151 | 1125 | ||
1152 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1153 | * and everything is OK. */ | ||
1154 | static int | ||
1155 | add_counter_to_entry(struct arpt_entry *e, | ||
1156 | const struct xt_counters addme[], | ||
1157 | unsigned int *i) | ||
1158 | { | ||
1159 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1160 | |||
1161 | (*i)++; | ||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | static int do_add_counters(struct net *net, const void __user *user, | 1126 | static int do_add_counters(struct net *net, const void __user *user, |
1166 | unsigned int len, int compat) | 1127 | unsigned int len, int compat) |
1167 | { | 1128 | { |
@@ -1234,9 +1195,10 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
1234 | curcpu = smp_processor_id(); | 1195 | curcpu = smp_processor_id(); |
1235 | loc_cpu_entry = private->entries[curcpu]; | 1196 | loc_cpu_entry = private->entries[curcpu]; |
1236 | xt_info_wrlock(curcpu); | 1197 | xt_info_wrlock(curcpu); |
1237 | xt_entry_foreach(iter, loc_cpu_entry, private->size) | 1198 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1238 | if (add_counter_to_entry(iter, paddc, &i) != 0) | 1199 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1239 | break; | 1200 | ++i; |
1201 | } | ||
1240 | xt_info_wrunlock(curcpu); | 1202 | xt_info_wrunlock(curcpu); |
1241 | unlock_up_free: | 1203 | unlock_up_free: |
1242 | local_bh_enable(); | 1204 | local_bh_enable(); |
@@ -1249,17 +1211,12 @@ static int do_add_counters(struct net *net, const void __user *user, | |||
1249 | } | 1211 | } |
1250 | 1212 | ||
1251 | #ifdef CONFIG_COMPAT | 1213 | #ifdef CONFIG_COMPAT |
1252 | static inline int | 1214 | static inline void compat_release_entry(struct compat_arpt_entry *e) |
1253 | compat_release_entry(struct compat_arpt_entry *e, unsigned int *i) | ||
1254 | { | 1215 | { |
1255 | struct arpt_entry_target *t; | 1216 | struct arpt_entry_target *t; |
1256 | 1217 | ||
1257 | if (i && (*i)-- == 0) | ||
1258 | return 1; | ||
1259 | |||
1260 | t = compat_arpt_get_target(e); | 1218 | t = compat_arpt_get_target(e); |
1261 | module_put(t->u.kernel.target->me); | 1219 | module_put(t->u.kernel.target->me); |
1262 | return 0; | ||
1263 | } | 1220 | } |
1264 | 1221 | ||
1265 | static inline int | 1222 | static inline int |
@@ -1270,7 +1227,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, | |||
1270 | const unsigned char *limit, | 1227 | const unsigned char *limit, |
1271 | const unsigned int *hook_entries, | 1228 | const unsigned int *hook_entries, |
1272 | const unsigned int *underflows, | 1229 | const unsigned int *underflows, |
1273 | unsigned int *i, | ||
1274 | const char *name) | 1230 | const char *name) |
1275 | { | 1231 | { |
1276 | struct arpt_entry_target *t; | 1232 | struct arpt_entry_target *t; |
@@ -1330,8 +1286,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, | |||
1330 | /* Clear counters and comefrom */ | 1286 | /* Clear counters and comefrom */ |
1331 | memset(&e->counters, 0, sizeof(e->counters)); | 1287 | memset(&e->counters, 0, sizeof(e->counters)); |
1332 | e->comefrom = 0; | 1288 | e->comefrom = 0; |
1333 | |||
1334 | (*i)++; | ||
1335 | return 0; | 1289 | return 0; |
1336 | 1290 | ||
1337 | release_target: | 1291 | release_target: |
@@ -1375,19 +1329,6 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, | |||
1375 | return ret; | 1329 | return ret; |
1376 | } | 1330 | } |
1377 | 1331 | ||
1378 | static inline int compat_check_entry(struct arpt_entry *e, const char *name, | ||
1379 | unsigned int *i) | ||
1380 | { | ||
1381 | int ret; | ||
1382 | |||
1383 | ret = check_target(e, name); | ||
1384 | if (ret) | ||
1385 | return ret; | ||
1386 | |||
1387 | (*i)++; | ||
1388 | return 0; | ||
1389 | } | ||
1390 | |||
1391 | static int translate_compat_table(const char *name, | 1332 | static int translate_compat_table(const char *name, |
1392 | unsigned int valid_hooks, | 1333 | unsigned int valid_hooks, |
1393 | struct xt_table_info **pinfo, | 1334 | struct xt_table_info **pinfo, |
@@ -1423,12 +1364,11 @@ static int translate_compat_table(const char *name, | |||
1423 | xt_entry_foreach(iter0, entry0, total_size) { | 1364 | xt_entry_foreach(iter0, entry0, total_size) { |
1424 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, | 1365 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
1425 | entry0, entry0 + total_size, hook_entries, underflows, | 1366 | entry0, entry0 + total_size, hook_entries, underflows, |
1426 | &j, name); | 1367 | name); |
1427 | if (ret != 0) | 1368 | if (ret != 0) |
1428 | break; | 1369 | goto out_unlock; |
1370 | ++j; | ||
1429 | } | 1371 | } |
1430 | if (ret != 0) | ||
1431 | goto out_unlock; | ||
1432 | 1372 | ||
1433 | ret = -EINVAL; | 1373 | ret = -EINVAL; |
1434 | if (j != number) { | 1374 | if (j != number) { |
@@ -1484,9 +1424,10 @@ static int translate_compat_table(const char *name, | |||
1484 | 1424 | ||
1485 | i = 0; | 1425 | i = 0; |
1486 | xt_entry_foreach(iter1, entry1, newinfo->size) { | 1426 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1487 | ret = compat_check_entry(iter1, name, &i); | 1427 | ret = check_target(iter1, name); |
1488 | if (ret != 0) | 1428 | if (ret != 0) |
1489 | break; | 1429 | break; |
1430 | ++i; | ||
1490 | } | 1431 | } |
1491 | if (ret) { | 1432 | if (ret) { |
1492 | /* | 1433 | /* |
@@ -1499,12 +1440,15 @@ static int translate_compat_table(const char *name, | |||
1499 | xt_entry_foreach(iter0, entry0, newinfo->size) { | 1440 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
1500 | if (skip-- > 0) | 1441 | if (skip-- > 0) |
1501 | continue; | 1442 | continue; |
1502 | if (compat_release_entry(iter0, &j) != 0) | 1443 | if (j-- == 0) |
1503 | break; | 1444 | break; |
1445 | compat_release_entry(iter0); | ||
1504 | } | 1446 | } |
1505 | xt_entry_foreach(iter1, entry1, newinfo->size) | 1447 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1506 | if (cleanup_entry(iter1, &i) != 0) | 1448 | if (i-- == 0) |
1507 | break; | 1449 | break; |
1450 | cleanup_entry(iter1); | ||
1451 | } | ||
1508 | xt_free_table_info(newinfo); | 1452 | xt_free_table_info(newinfo); |
1509 | return ret; | 1453 | return ret; |
1510 | } | 1454 | } |
@@ -1522,9 +1466,11 @@ static int translate_compat_table(const char *name, | |||
1522 | free_newinfo: | 1466 | free_newinfo: |
1523 | xt_free_table_info(newinfo); | 1467 | xt_free_table_info(newinfo); |
1524 | out: | 1468 | out: |
1525 | xt_entry_foreach(iter0, entry0, total_size) | 1469 | xt_entry_foreach(iter0, entry0, total_size) { |
1526 | if (compat_release_entry(iter0, &j) != 0) | 1470 | if (j-- == 0) |
1527 | break; | 1471 | break; |
1472 | compat_release_entry(iter0); | ||
1473 | } | ||
1528 | return ret; | 1474 | return ret; |
1529 | out_unlock: | 1475 | out_unlock: |
1530 | xt_compat_flush_offsets(NFPROTO_ARP); | 1476 | xt_compat_flush_offsets(NFPROTO_ARP); |
@@ -1590,8 +1536,7 @@ static int compat_do_replace(struct net *net, void __user *user, | |||
1590 | 1536 | ||
1591 | free_newinfo_untrans: | 1537 | free_newinfo_untrans: |
1592 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) | 1538 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1593 | if (cleanup_entry(iter, NULL) != 0) | 1539 | cleanup_entry(iter); |
1594 | break; | ||
1595 | free_newinfo: | 1540 | free_newinfo: |
1596 | xt_free_table_info(newinfo); | 1541 | xt_free_table_info(newinfo); |
1597 | return ret; | 1542 | return ret; |
@@ -1625,7 +1570,7 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, | |||
1625 | static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | 1570 | static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, |
1626 | compat_uint_t *size, | 1571 | compat_uint_t *size, |
1627 | struct xt_counters *counters, | 1572 | struct xt_counters *counters, |
1628 | unsigned int *i) | 1573 | unsigned int i) |
1629 | { | 1574 | { |
1630 | struct arpt_entry_target *t; | 1575 | struct arpt_entry_target *t; |
1631 | struct compat_arpt_entry __user *ce; | 1576 | struct compat_arpt_entry __user *ce; |
@@ -1633,14 +1578,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | |||
1633 | compat_uint_t origsize; | 1578 | compat_uint_t origsize; |
1634 | int ret; | 1579 | int ret; |
1635 | 1580 | ||
1636 | ret = -EFAULT; | ||
1637 | origsize = *size; | 1581 | origsize = *size; |
1638 | ce = (struct compat_arpt_entry __user *)*dstptr; | 1582 | ce = (struct compat_arpt_entry __user *)*dstptr; |
1639 | if (copy_to_user(ce, e, sizeof(struct arpt_entry))) | 1583 | if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || |
1640 | goto out; | 1584 | copy_to_user(&ce->counters, &counters[i], |
1641 | 1585 | sizeof(counters[i])) != 0) | |
1642 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1586 | return -EFAULT; |
1643 | goto out; | ||
1644 | 1587 | ||
1645 | *dstptr += sizeof(struct compat_arpt_entry); | 1588 | *dstptr += sizeof(struct compat_arpt_entry); |
1646 | *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); | 1589 | *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); |
@@ -1650,18 +1593,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, | |||
1650 | t = arpt_get_target(e); | 1593 | t = arpt_get_target(e); |
1651 | ret = xt_compat_target_to_user(t, dstptr, size); | 1594 | ret = xt_compat_target_to_user(t, dstptr, size); |
1652 | if (ret) | 1595 | if (ret) |
1653 | goto out; | 1596 | return ret; |
1654 | ret = -EFAULT; | ||
1655 | next_offset = e->next_offset - (origsize - *size); | 1597 | next_offset = e->next_offset - (origsize - *size); |
1656 | if (put_user(target_offset, &ce->target_offset)) | 1598 | if (put_user(target_offset, &ce->target_offset) != 0 || |
1657 | goto out; | 1599 | put_user(next_offset, &ce->next_offset) != 0) |
1658 | if (put_user(next_offset, &ce->next_offset)) | 1600 | return -EFAULT; |
1659 | goto out; | ||
1660 | |||
1661 | (*i)++; | ||
1662 | return 0; | 1601 | return 0; |
1663 | out: | ||
1664 | return ret; | ||
1665 | } | 1602 | } |
1666 | 1603 | ||
1667 | static int compat_copy_entries_to_user(unsigned int total_size, | 1604 | static int compat_copy_entries_to_user(unsigned int total_size, |
@@ -1687,7 +1624,7 @@ static int compat_copy_entries_to_user(unsigned int total_size, | |||
1687 | size = total_size; | 1624 | size = total_size; |
1688 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { | 1625 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
1689 | ret = compat_copy_entry_to_user(iter, &pos, | 1626 | ret = compat_copy_entry_to_user(iter, &pos, |
1690 | &size, counters, &i); | 1627 | &size, counters, i++); |
1691 | if (ret != 0) | 1628 | if (ret != 0) |
1692 | break; | 1629 | break; |
1693 | } | 1630 | } |
@@ -1893,8 +1830,7 @@ void arpt_unregister_table(struct xt_table *table) | |||
1893 | /* Decrease module usage counts and free resources */ | 1830 | /* Decrease module usage counts and free resources */ |
1894 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1831 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
1895 | xt_entry_foreach(iter, loc_cpu_entry, private->size) | 1832 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
1896 | if (cleanup_entry(iter, NULL) != 0) | 1833 | cleanup_entry(iter); |
1897 | break; | ||
1898 | if (private->number > private->initial_entries) | 1834 | if (private->number > private->initial_entries) |
1899 | module_put(table_owner); | 1835 | module_put(table_owner); |
1900 | xt_free_table_info(private); | 1836 | xt_free_table_info(private); |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index b43280aad8a2..9c8aa394c51c 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -679,7 +679,7 @@ static int check_target(struct ipt_entry *e, struct net *net, const char *name) | |||
679 | 679 | ||
680 | static int | 680 | static int |
681 | find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | 681 | find_check_entry(struct ipt_entry *e, struct net *net, const char *name, |
682 | unsigned int size, unsigned int *i) | 682 | unsigned int size) |
683 | { | 683 | { |
684 | struct ipt_entry_target *t; | 684 | struct ipt_entry_target *t; |
685 | struct xt_target *target; | 685 | struct xt_target *target; |
@@ -716,8 +716,6 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
716 | ret = check_target(e, net, name); | 716 | ret = check_target(e, net, name); |
717 | if (ret) | 717 | if (ret) |
718 | goto err; | 718 | goto err; |
719 | |||
720 | (*i)++; | ||
721 | return 0; | 719 | return 0; |
722 | err: | 720 | err: |
723 | module_put(t->u.kernel.target->me); | 721 | module_put(t->u.kernel.target->me); |
@@ -748,8 +746,7 @@ check_entry_size_and_hooks(struct ipt_entry *e, | |||
748 | const unsigned char *limit, | 746 | const unsigned char *limit, |
749 | const unsigned int *hook_entries, | 747 | const unsigned int *hook_entries, |
750 | const unsigned int *underflows, | 748 | const unsigned int *underflows, |
751 | unsigned int valid_hooks, | 749 | unsigned int valid_hooks) |
752 | unsigned int *i) | ||
753 | { | 750 | { |
754 | unsigned int h; | 751 | unsigned int h; |
755 | 752 | ||
@@ -786,20 +783,15 @@ check_entry_size_and_hooks(struct ipt_entry *e, | |||
786 | /* Clear counters and comefrom */ | 783 | /* Clear counters and comefrom */ |
787 | e->counters = ((struct xt_counters) { 0, 0 }); | 784 | e->counters = ((struct xt_counters) { 0, 0 }); |
788 | e->comefrom = 0; | 785 | e->comefrom = 0; |
789 | |||
790 | (*i)++; | ||
791 | return 0; | 786 | return 0; |
792 | } | 787 | } |
793 | 788 | ||
794 | static int | 789 | static void |
795 | cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) | 790 | cleanup_entry(struct ipt_entry *e, struct net *net) |
796 | { | 791 | { |
797 | struct xt_tgdtor_param par; | 792 | struct xt_tgdtor_param par; |
798 | struct ipt_entry_target *t; | 793 | struct ipt_entry_target *t; |
799 | 794 | ||
800 | if (i && (*i)-- == 0) | ||
801 | return 1; | ||
802 | |||
803 | /* Cleanup all matches */ | 795 | /* Cleanup all matches */ |
804 | IPT_MATCH_ITERATE(e, cleanup_match, net, NULL); | 796 | IPT_MATCH_ITERATE(e, cleanup_match, net, NULL); |
805 | t = ipt_get_target(e); | 797 | t = ipt_get_target(e); |
@@ -811,7 +803,6 @@ cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i) | |||
811 | if (par.target->destroy != NULL) | 803 | if (par.target->destroy != NULL) |
812 | par.target->destroy(&par); | 804 | par.target->destroy(&par); |
813 | module_put(par.target->me); | 805 | module_put(par.target->me); |
814 | return 0; | ||
815 | } | 806 | } |
816 | 807 | ||
817 | /* Checks and translates the user-supplied table segment (held in | 808 | /* Checks and translates the user-supplied table segment (held in |
@@ -845,13 +836,11 @@ translate_table(struct net *net, | |||
845 | /* Walk through entries, checking offsets. */ | 836 | /* Walk through entries, checking offsets. */ |
846 | xt_entry_foreach(iter, entry0, newinfo->size) { | 837 | xt_entry_foreach(iter, entry0, newinfo->size) { |
847 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, | 838 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
848 | entry0 + size, hook_entries, underflows, | 839 | entry0 + size, hook_entries, underflows, valid_hooks); |
849 | valid_hooks, &i); | ||
850 | if (ret != 0) | 840 | if (ret != 0) |
851 | break; | 841 | return ret; |
842 | ++i; | ||
852 | } | 843 | } |
853 | if (ret != 0) | ||
854 | return ret; | ||
855 | 844 | ||
856 | if (i != number) { | 845 | if (i != number) { |
857 | duprintf("translate_table: %u not %u entries\n", | 846 | duprintf("translate_table: %u not %u entries\n", |
@@ -882,15 +871,18 @@ translate_table(struct net *net, | |||
882 | /* Finally, each sanity check must pass */ | 871 | /* Finally, each sanity check must pass */ |
883 | i = 0; | 872 | i = 0; |
884 | xt_entry_foreach(iter, entry0, newinfo->size) { | 873 | xt_entry_foreach(iter, entry0, newinfo->size) { |
885 | ret = find_check_entry(iter, net, name, size, &i); | 874 | ret = find_check_entry(iter, net, name, size); |
886 | if (ret != 0) | 875 | if (ret != 0) |
887 | break; | 876 | break; |
877 | ++i; | ||
888 | } | 878 | } |
889 | 879 | ||
890 | if (ret != 0) { | 880 | if (ret != 0) { |
891 | xt_entry_foreach(iter, entry0, newinfo->size) | 881 | xt_entry_foreach(iter, entry0, newinfo->size) { |
892 | if (cleanup_entry(iter, net, &i) != 0) | 882 | if (i-- == 0) |
893 | break; | 883 | break; |
884 | cleanup_entry(iter, net); | ||
885 | } | ||
894 | return ret; | 886 | return ret; |
895 | } | 887 | } |
896 | 888 | ||
@@ -903,29 +895,6 @@ translate_table(struct net *net, | |||
903 | return ret; | 895 | return ret; |
904 | } | 896 | } |
905 | 897 | ||
906 | /* Gets counters. */ | ||
907 | static inline int | ||
908 | add_entry_to_counter(const struct ipt_entry *e, | ||
909 | struct xt_counters total[], | ||
910 | unsigned int *i) | ||
911 | { | ||
912 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
913 | |||
914 | (*i)++; | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | static inline int | ||
919 | set_entry_to_counter(const struct ipt_entry *e, | ||
920 | struct ipt_counters total[], | ||
921 | unsigned int *i) | ||
922 | { | ||
923 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
924 | |||
925 | (*i)++; | ||
926 | return 0; | ||
927 | } | ||
928 | |||
929 | static void | 898 | static void |
930 | get_counters(const struct xt_table_info *t, | 899 | get_counters(const struct xt_table_info *t, |
931 | struct xt_counters counters[]) | 900 | struct xt_counters counters[]) |
@@ -946,18 +915,22 @@ get_counters(const struct xt_table_info *t, | |||
946 | curcpu = smp_processor_id(); | 915 | curcpu = smp_processor_id(); |
947 | 916 | ||
948 | i = 0; | 917 | i = 0; |
949 | xt_entry_foreach(iter, t->entries[curcpu], t->size) | 918 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
950 | if (set_entry_to_counter(iter, counters, &i) != 0) | 919 | SET_COUNTER(counters[i], iter->counters.bcnt, |
951 | break; | 920 | iter->counters.pcnt); |
921 | ++i; | ||
922 | } | ||
952 | 923 | ||
953 | for_each_possible_cpu(cpu) { | 924 | for_each_possible_cpu(cpu) { |
954 | if (cpu == curcpu) | 925 | if (cpu == curcpu) |
955 | continue; | 926 | continue; |
956 | i = 0; | 927 | i = 0; |
957 | xt_info_wrlock(cpu); | 928 | xt_info_wrlock(cpu); |
958 | xt_entry_foreach(iter, t->entries[cpu], t->size) | 929 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
959 | if (add_entry_to_counter(iter, counters, &i) != 0) | 930 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
960 | break; | 931 | iter->counters.pcnt); |
932 | ++i; /* macro does multi eval of i */ | ||
933 | } | ||
961 | xt_info_wrunlock(cpu); | 934 | xt_info_wrunlock(cpu); |
962 | } | 935 | } |
963 | local_bh_enable(); | 936 | local_bh_enable(); |
@@ -1117,7 +1090,7 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1117 | { | 1090 | { |
1118 | struct ipt_entry *iter; | 1091 | struct ipt_entry *iter; |
1119 | void *loc_cpu_entry; | 1092 | void *loc_cpu_entry; |
1120 | int ret = 0; | 1093 | int ret; |
1121 | 1094 | ||
1122 | if (!newinfo || !info) | 1095 | if (!newinfo || !info) |
1123 | return -EINVAL; | 1096 | return -EINVAL; |
@@ -1129,9 +1102,9 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1129 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { | 1102 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
1130 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); | 1103 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
1131 | if (ret != 0) | 1104 | if (ret != 0) |
1132 | break; | 1105 | return ret; |
1133 | } | 1106 | } |
1134 | return ret; | 1107 | return 0; |
1135 | } | 1108 | } |
1136 | #endif | 1109 | #endif |
1137 | 1110 | ||
@@ -1289,8 +1262,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1289 | /* Decrease module usage counts and free resource */ | 1262 | /* Decrease module usage counts and free resource */ |
1290 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1263 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
1291 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) | 1264 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
1292 | if (cleanup_entry(iter, net, NULL) != 0) | 1265 | cleanup_entry(iter, net); |
1293 | break; | ||
1294 | 1266 | ||
1295 | xt_free_table_info(oldinfo); | 1267 | xt_free_table_info(oldinfo); |
1296 | if (copy_to_user(counters_ptr, counters, | 1268 | if (copy_to_user(counters_ptr, counters, |
@@ -1353,26 +1325,12 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1353 | 1325 | ||
1354 | free_newinfo_untrans: | 1326 | free_newinfo_untrans: |
1355 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) | 1327 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1356 | if (cleanup_entry(iter, net, NULL) != 0) | 1328 | cleanup_entry(iter, net); |
1357 | break; | ||
1358 | free_newinfo: | 1329 | free_newinfo: |
1359 | xt_free_table_info(newinfo); | 1330 | xt_free_table_info(newinfo); |
1360 | return ret; | 1331 | return ret; |
1361 | } | 1332 | } |
1362 | 1333 | ||
1363 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1364 | * and everything is OK. */ | ||
1365 | static int | ||
1366 | add_counter_to_entry(struct ipt_entry *e, | ||
1367 | const struct xt_counters addme[], | ||
1368 | unsigned int *i) | ||
1369 | { | ||
1370 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1371 | |||
1372 | (*i)++; | ||
1373 | return 0; | ||
1374 | } | ||
1375 | |||
1376 | static int | 1334 | static int |
1377 | do_add_counters(struct net *net, const void __user *user, | 1335 | do_add_counters(struct net *net, const void __user *user, |
1378 | unsigned int len, int compat) | 1336 | unsigned int len, int compat) |
@@ -1446,9 +1404,10 @@ do_add_counters(struct net *net, const void __user *user, | |||
1446 | curcpu = smp_processor_id(); | 1404 | curcpu = smp_processor_id(); |
1447 | loc_cpu_entry = private->entries[curcpu]; | 1405 | loc_cpu_entry = private->entries[curcpu]; |
1448 | xt_info_wrlock(curcpu); | 1406 | xt_info_wrlock(curcpu); |
1449 | xt_entry_foreach(iter, loc_cpu_entry, private->size) | 1407 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1450 | if (add_counter_to_entry(iter, paddc, &i) != 0) | 1408 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1451 | break; | 1409 | ++i; |
1410 | } | ||
1452 | xt_info_wrunlock(curcpu); | 1411 | xt_info_wrunlock(curcpu); |
1453 | unlock_up_free: | 1412 | unlock_up_free: |
1454 | local_bh_enable(); | 1413 | local_bh_enable(); |
@@ -1476,7 +1435,7 @@ struct compat_ipt_replace { | |||
1476 | static int | 1435 | static int |
1477 | compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, | 1436 | compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, |
1478 | unsigned int *size, struct xt_counters *counters, | 1437 | unsigned int *size, struct xt_counters *counters, |
1479 | unsigned int *i) | 1438 | unsigned int i) |
1480 | { | 1439 | { |
1481 | struct ipt_entry_target *t; | 1440 | struct ipt_entry_target *t; |
1482 | struct compat_ipt_entry __user *ce; | 1441 | struct compat_ipt_entry __user *ce; |
@@ -1484,14 +1443,12 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, | |||
1484 | compat_uint_t origsize; | 1443 | compat_uint_t origsize; |
1485 | int ret; | 1444 | int ret; |
1486 | 1445 | ||
1487 | ret = -EFAULT; | ||
1488 | origsize = *size; | 1446 | origsize = *size; |
1489 | ce = (struct compat_ipt_entry __user *)*dstptr; | 1447 | ce = (struct compat_ipt_entry __user *)*dstptr; |
1490 | if (copy_to_user(ce, e, sizeof(struct ipt_entry))) | 1448 | if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || |
1491 | goto out; | 1449 | copy_to_user(&ce->counters, &counters[i], |
1492 | 1450 | sizeof(counters[i])) != 0) | |
1493 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1451 | return -EFAULT; |
1494 | goto out; | ||
1495 | 1452 | ||
1496 | *dstptr += sizeof(struct compat_ipt_entry); | 1453 | *dstptr += sizeof(struct compat_ipt_entry); |
1497 | *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); | 1454 | *size -= sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); |
@@ -1499,22 +1456,16 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr, | |||
1499 | ret = IPT_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); | 1456 | ret = IPT_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); |
1500 | target_offset = e->target_offset - (origsize - *size); | 1457 | target_offset = e->target_offset - (origsize - *size); |
1501 | if (ret) | 1458 | if (ret) |
1502 | goto out; | 1459 | return ret; |
1503 | t = ipt_get_target(e); | 1460 | t = ipt_get_target(e); |
1504 | ret = xt_compat_target_to_user(t, dstptr, size); | 1461 | ret = xt_compat_target_to_user(t, dstptr, size); |
1505 | if (ret) | 1462 | if (ret) |
1506 | goto out; | 1463 | return ret; |
1507 | ret = -EFAULT; | ||
1508 | next_offset = e->next_offset - (origsize - *size); | 1464 | next_offset = e->next_offset - (origsize - *size); |
1509 | if (put_user(target_offset, &ce->target_offset)) | 1465 | if (put_user(target_offset, &ce->target_offset) != 0 || |
1510 | goto out; | 1466 | put_user(next_offset, &ce->next_offset) != 0) |
1511 | if (put_user(next_offset, &ce->next_offset)) | 1467 | return -EFAULT; |
1512 | goto out; | ||
1513 | |||
1514 | (*i)++; | ||
1515 | return 0; | 1468 | return 0; |
1516 | out: | ||
1517 | return ret; | ||
1518 | } | 1469 | } |
1519 | 1470 | ||
1520 | static int | 1471 | static int |
@@ -1551,19 +1502,14 @@ compat_release_match(struct ipt_entry_match *m, unsigned int *i) | |||
1551 | return 0; | 1502 | return 0; |
1552 | } | 1503 | } |
1553 | 1504 | ||
1554 | static int | 1505 | static void compat_release_entry(struct compat_ipt_entry *e) |
1555 | compat_release_entry(struct compat_ipt_entry *e, unsigned int *i) | ||
1556 | { | 1506 | { |
1557 | struct ipt_entry_target *t; | 1507 | struct ipt_entry_target *t; |
1558 | 1508 | ||
1559 | if (i && (*i)-- == 0) | ||
1560 | return 1; | ||
1561 | |||
1562 | /* Cleanup all matches */ | 1509 | /* Cleanup all matches */ |
1563 | COMPAT_IPT_MATCH_ITERATE(e, compat_release_match, NULL); | 1510 | COMPAT_IPT_MATCH_ITERATE(e, compat_release_match, NULL); |
1564 | t = compat_ipt_get_target(e); | 1511 | t = compat_ipt_get_target(e); |
1565 | module_put(t->u.kernel.target->me); | 1512 | module_put(t->u.kernel.target->me); |
1566 | return 0; | ||
1567 | } | 1513 | } |
1568 | 1514 | ||
1569 | static int | 1515 | static int |
@@ -1574,7 +1520,6 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
1574 | const unsigned char *limit, | 1520 | const unsigned char *limit, |
1575 | const unsigned int *hook_entries, | 1521 | const unsigned int *hook_entries, |
1576 | const unsigned int *underflows, | 1522 | const unsigned int *underflows, |
1577 | unsigned int *i, | ||
1578 | const char *name) | 1523 | const char *name) |
1579 | { | 1524 | { |
1580 | struct ipt_entry_target *t; | 1525 | struct ipt_entry_target *t; |
@@ -1640,8 +1585,6 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
1640 | /* Clear counters and comefrom */ | 1585 | /* Clear counters and comefrom */ |
1641 | memset(&e->counters, 0, sizeof(e->counters)); | 1586 | memset(&e->counters, 0, sizeof(e->counters)); |
1642 | e->comefrom = 0; | 1587 | e->comefrom = 0; |
1643 | |||
1644 | (*i)++; | ||
1645 | return 0; | 1588 | return 0; |
1646 | 1589 | ||
1647 | out: | 1590 | out: |
@@ -1691,8 +1634,7 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr, | |||
1691 | } | 1634 | } |
1692 | 1635 | ||
1693 | static int | 1636 | static int |
1694 | compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, | 1637 | compat_check_entry(struct ipt_entry *e, struct net *net, const char *name) |
1695 | unsigned int *i) | ||
1696 | { | 1638 | { |
1697 | struct xt_mtchk_param mtpar; | 1639 | struct xt_mtchk_param mtpar; |
1698 | unsigned int j; | 1640 | unsigned int j; |
@@ -1711,8 +1653,6 @@ compat_check_entry(struct ipt_entry *e, struct net *net, const char *name, | |||
1711 | ret = check_target(e, net, name); | 1653 | ret = check_target(e, net, name); |
1712 | if (ret) | 1654 | if (ret) |
1713 | goto cleanup_matches; | 1655 | goto cleanup_matches; |
1714 | |||
1715 | (*i)++; | ||
1716 | return 0; | 1656 | return 0; |
1717 | 1657 | ||
1718 | cleanup_matches: | 1658 | cleanup_matches: |
@@ -1737,7 +1677,7 @@ translate_compat_table(struct net *net, | |||
1737 | struct compat_ipt_entry *iter0; | 1677 | struct compat_ipt_entry *iter0; |
1738 | struct ipt_entry *iter1; | 1678 | struct ipt_entry *iter1; |
1739 | unsigned int size; | 1679 | unsigned int size; |
1740 | int ret = 0; | 1680 | int ret; |
1741 | 1681 | ||
1742 | info = *pinfo; | 1682 | info = *pinfo; |
1743 | entry0 = *pentry0; | 1683 | entry0 = *pentry0; |
@@ -1757,12 +1697,11 @@ translate_compat_table(struct net *net, | |||
1757 | xt_entry_foreach(iter0, entry0, total_size) { | 1697 | xt_entry_foreach(iter0, entry0, total_size) { |
1758 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, | 1698 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
1759 | entry0, entry0 + total_size, hook_entries, underflows, | 1699 | entry0, entry0 + total_size, hook_entries, underflows, |
1760 | &j, name); | 1700 | name); |
1761 | if (ret != 0) | 1701 | if (ret != 0) |
1762 | break; | 1702 | goto out_unlock; |
1703 | ++j; | ||
1763 | } | 1704 | } |
1764 | if (ret != 0) | ||
1765 | goto out_unlock; | ||
1766 | 1705 | ||
1767 | ret = -EINVAL; | 1706 | ret = -EINVAL; |
1768 | if (j != number) { | 1707 | if (j != number) { |
@@ -1818,9 +1757,10 @@ translate_compat_table(struct net *net, | |||
1818 | 1757 | ||
1819 | i = 0; | 1758 | i = 0; |
1820 | xt_entry_foreach(iter1, entry1, newinfo->size) { | 1759 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1821 | ret = compat_check_entry(iter1, net, name, &i); | 1760 | ret = compat_check_entry(iter1, net, name); |
1822 | if (ret != 0) | 1761 | if (ret != 0) |
1823 | break; | 1762 | break; |
1763 | ++i; | ||
1824 | } | 1764 | } |
1825 | if (ret) { | 1765 | if (ret) { |
1826 | /* | 1766 | /* |
@@ -1833,12 +1773,15 @@ translate_compat_table(struct net *net, | |||
1833 | xt_entry_foreach(iter0, entry0, newinfo->size) { | 1773 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
1834 | if (skip-- > 0) | 1774 | if (skip-- > 0) |
1835 | continue; | 1775 | continue; |
1836 | if (compat_release_entry(iter0, &i) != 0) | 1776 | if (j-- == 0) |
1837 | break; | 1777 | break; |
1778 | compat_release_entry(iter0); | ||
1838 | } | 1779 | } |
1839 | xt_entry_foreach(iter1, entry1, newinfo->size) | 1780 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1840 | if (cleanup_entry(iter1, net, &i) != 0) | 1781 | if (i-- == 0) |
1841 | break; | 1782 | break; |
1783 | cleanup_entry(iter1, net); | ||
1784 | } | ||
1842 | xt_free_table_info(newinfo); | 1785 | xt_free_table_info(newinfo); |
1843 | return ret; | 1786 | return ret; |
1844 | } | 1787 | } |
@@ -1856,9 +1799,11 @@ translate_compat_table(struct net *net, | |||
1856 | free_newinfo: | 1799 | free_newinfo: |
1857 | xt_free_table_info(newinfo); | 1800 | xt_free_table_info(newinfo); |
1858 | out: | 1801 | out: |
1859 | xt_entry_foreach(iter0, entry0, total_size) | 1802 | xt_entry_foreach(iter0, entry0, total_size) { |
1860 | if (compat_release_entry(iter0, &j) != 0) | 1803 | if (j-- == 0) |
1861 | break; | 1804 | break; |
1805 | compat_release_entry(iter0); | ||
1806 | } | ||
1862 | return ret; | 1807 | return ret; |
1863 | out_unlock: | 1808 | out_unlock: |
1864 | xt_compat_flush_offsets(AF_INET); | 1809 | xt_compat_flush_offsets(AF_INET); |
@@ -1913,8 +1858,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1913 | 1858 | ||
1914 | free_newinfo_untrans: | 1859 | free_newinfo_untrans: |
1915 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) | 1860 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1916 | if (cleanup_entry(iter, net, NULL) != 0) | 1861 | cleanup_entry(iter, net); |
1917 | break; | ||
1918 | free_newinfo: | 1862 | free_newinfo: |
1919 | xt_free_table_info(newinfo); | 1863 | xt_free_table_info(newinfo); |
1920 | return ret; | 1864 | return ret; |
@@ -1978,7 +1922,7 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
1978 | size = total_size; | 1922 | size = total_size; |
1979 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { | 1923 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
1980 | ret = compat_copy_entry_to_user(iter, &pos, | 1924 | ret = compat_copy_entry_to_user(iter, &pos, |
1981 | &size, counters, &i); | 1925 | &size, counters, i++); |
1982 | if (ret != 0) | 1926 | if (ret != 0) |
1983 | break; | 1927 | break; |
1984 | } | 1928 | } |
@@ -2189,8 +2133,7 @@ void ipt_unregister_table(struct net *net, struct xt_table *table) | |||
2189 | /* Decrease module usage counts and free resources */ | 2133 | /* Decrease module usage counts and free resources */ |
2190 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 2134 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
2191 | xt_entry_foreach(iter, loc_cpu_entry, private->size) | 2135 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
2192 | if (cleanup_entry(iter, net, NULL) != 0) | 2136 | cleanup_entry(iter, net); |
2193 | break; | ||
2194 | if (private->number > private->initial_entries) | 2137 | if (private->number > private->initial_entries) |
2195 | module_put(table_owner); | 2138 | module_put(table_owner); |
2196 | xt_free_table_info(private); | 2139 | xt_free_table_info(private); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 23926e38d36b..b7e27c19c7ab 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -710,7 +710,7 @@ static int check_target(struct ip6t_entry *e, struct net *net, const char *name) | |||
710 | 710 | ||
711 | static int | 711 | static int |
712 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | 712 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, |
713 | unsigned int size, unsigned int *i) | 713 | unsigned int size) |
714 | { | 714 | { |
715 | struct ip6t_entry_target *t; | 715 | struct ip6t_entry_target *t; |
716 | struct xt_target *target; | 716 | struct xt_target *target; |
@@ -747,8 +747,6 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | |||
747 | ret = check_target(e, net, name); | 747 | ret = check_target(e, net, name); |
748 | if (ret) | 748 | if (ret) |
749 | goto err; | 749 | goto err; |
750 | |||
751 | (*i)++; | ||
752 | return 0; | 750 | return 0; |
753 | err: | 751 | err: |
754 | module_put(t->u.kernel.target->me); | 752 | module_put(t->u.kernel.target->me); |
@@ -779,8 +777,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
779 | const unsigned char *limit, | 777 | const unsigned char *limit, |
780 | const unsigned int *hook_entries, | 778 | const unsigned int *hook_entries, |
781 | const unsigned int *underflows, | 779 | const unsigned int *underflows, |
782 | unsigned int valid_hooks, | 780 | unsigned int valid_hooks) |
783 | unsigned int *i) | ||
784 | { | 781 | { |
785 | unsigned int h; | 782 | unsigned int h; |
786 | 783 | ||
@@ -817,20 +814,14 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
817 | /* Clear counters and comefrom */ | 814 | /* Clear counters and comefrom */ |
818 | e->counters = ((struct xt_counters) { 0, 0 }); | 815 | e->counters = ((struct xt_counters) { 0, 0 }); |
819 | e->comefrom = 0; | 816 | e->comefrom = 0; |
820 | |||
821 | (*i)++; | ||
822 | return 0; | 817 | return 0; |
823 | } | 818 | } |
824 | 819 | ||
825 | static int | 820 | static void cleanup_entry(struct ip6t_entry *e, struct net *net) |
826 | cleanup_entry(struct ip6t_entry *e, struct net *net, unsigned int *i) | ||
827 | { | 821 | { |
828 | struct xt_tgdtor_param par; | 822 | struct xt_tgdtor_param par; |
829 | struct ip6t_entry_target *t; | 823 | struct ip6t_entry_target *t; |
830 | 824 | ||
831 | if (i && (*i)-- == 0) | ||
832 | return 1; | ||
833 | |||
834 | /* Cleanup all matches */ | 825 | /* Cleanup all matches */ |
835 | IP6T_MATCH_ITERATE(e, cleanup_match, net, NULL); | 826 | IP6T_MATCH_ITERATE(e, cleanup_match, net, NULL); |
836 | t = ip6t_get_target(e); | 827 | t = ip6t_get_target(e); |
@@ -842,7 +833,6 @@ cleanup_entry(struct ip6t_entry *e, struct net *net, unsigned int *i) | |||
842 | if (par.target->destroy != NULL) | 833 | if (par.target->destroy != NULL) |
843 | par.target->destroy(&par); | 834 | par.target->destroy(&par); |
844 | module_put(par.target->me); | 835 | module_put(par.target->me); |
845 | return 0; | ||
846 | } | 836 | } |
847 | 837 | ||
848 | /* Checks and translates the user-supplied table segment (held in | 838 | /* Checks and translates the user-supplied table segment (held in |
@@ -876,13 +866,11 @@ translate_table(struct net *net, | |||
876 | /* Walk through entries, checking offsets. */ | 866 | /* Walk through entries, checking offsets. */ |
877 | xt_entry_foreach(iter, entry0, newinfo->size) { | 867 | xt_entry_foreach(iter, entry0, newinfo->size) { |
878 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, | 868 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
879 | entry0 + size, hook_entries, underflows, | 869 | entry0 + size, hook_entries, underflows, valid_hooks); |
880 | valid_hooks, &i); | ||
881 | if (ret != 0) | 870 | if (ret != 0) |
882 | break; | 871 | return ret; |
872 | ++i; | ||
883 | } | 873 | } |
884 | if (ret != 0) | ||
885 | return ret; | ||
886 | 874 | ||
887 | if (i != number) { | 875 | if (i != number) { |
888 | duprintf("translate_table: %u not %u entries\n", | 876 | duprintf("translate_table: %u not %u entries\n", |
@@ -913,15 +901,18 @@ translate_table(struct net *net, | |||
913 | /* Finally, each sanity check must pass */ | 901 | /* Finally, each sanity check must pass */ |
914 | i = 0; | 902 | i = 0; |
915 | xt_entry_foreach(iter, entry0, newinfo->size) { | 903 | xt_entry_foreach(iter, entry0, newinfo->size) { |
916 | ret = find_check_entry(iter, net, name, size, &i); | 904 | ret = find_check_entry(iter, net, name, size); |
917 | if (ret != 0) | 905 | if (ret != 0) |
918 | break; | 906 | break; |
907 | ++i; | ||
919 | } | 908 | } |
920 | 909 | ||
921 | if (ret != 0) { | 910 | if (ret != 0) { |
922 | xt_entry_foreach(iter, entry0, newinfo->size) | 911 | xt_entry_foreach(iter, entry0, newinfo->size) { |
923 | if (cleanup_entry(iter, net, &i) != 0) | 912 | if (i-- == 0) |
924 | break; | 913 | break; |
914 | cleanup_entry(iter, net); | ||
915 | } | ||
925 | return ret; | 916 | return ret; |
926 | } | 917 | } |
927 | 918 | ||
@@ -934,29 +925,6 @@ translate_table(struct net *net, | |||
934 | return ret; | 925 | return ret; |
935 | } | 926 | } |
936 | 927 | ||
937 | /* Gets counters. */ | ||
938 | static inline int | ||
939 | add_entry_to_counter(const struct ip6t_entry *e, | ||
940 | struct xt_counters total[], | ||
941 | unsigned int *i) | ||
942 | { | ||
943 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
944 | |||
945 | (*i)++; | ||
946 | return 0; | ||
947 | } | ||
948 | |||
949 | static inline int | ||
950 | set_entry_to_counter(const struct ip6t_entry *e, | ||
951 | struct ip6t_counters total[], | ||
952 | unsigned int *i) | ||
953 | { | ||
954 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
955 | |||
956 | (*i)++; | ||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | static void | 928 | static void |
961 | get_counters(const struct xt_table_info *t, | 929 | get_counters(const struct xt_table_info *t, |
962 | struct xt_counters counters[]) | 930 | struct xt_counters counters[]) |
@@ -977,18 +945,22 @@ get_counters(const struct xt_table_info *t, | |||
977 | curcpu = smp_processor_id(); | 945 | curcpu = smp_processor_id(); |
978 | 946 | ||
979 | i = 0; | 947 | i = 0; |
980 | xt_entry_foreach(iter, t->entries[curcpu], t->size) | 948 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
981 | if (set_entry_to_counter(iter, counters, &i) != 0) | 949 | SET_COUNTER(counters[i], iter->counters.bcnt, |
982 | break; | 950 | iter->counters.pcnt); |
951 | ++i; | ||
952 | } | ||
983 | 953 | ||
984 | for_each_possible_cpu(cpu) { | 954 | for_each_possible_cpu(cpu) { |
985 | if (cpu == curcpu) | 955 | if (cpu == curcpu) |
986 | continue; | 956 | continue; |
987 | i = 0; | 957 | i = 0; |
988 | xt_info_wrlock(cpu); | 958 | xt_info_wrlock(cpu); |
989 | xt_entry_foreach(iter, t->entries[cpu], t->size) | 959 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
990 | if (add_entry_to_counter(iter, counters, &i) != 0) | 960 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
991 | break; | 961 | iter->counters.pcnt); |
962 | ++i; | ||
963 | } | ||
992 | xt_info_wrunlock(cpu); | 964 | xt_info_wrunlock(cpu); |
993 | } | 965 | } |
994 | local_bh_enable(); | 966 | local_bh_enable(); |
@@ -1148,7 +1120,7 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1148 | { | 1120 | { |
1149 | struct ip6t_entry *iter; | 1121 | struct ip6t_entry *iter; |
1150 | void *loc_cpu_entry; | 1122 | void *loc_cpu_entry; |
1151 | int ret = 0; | 1123 | int ret; |
1152 | 1124 | ||
1153 | if (!newinfo || !info) | 1125 | if (!newinfo || !info) |
1154 | return -EINVAL; | 1126 | return -EINVAL; |
@@ -1160,9 +1132,9 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1160 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { | 1132 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
1161 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); | 1133 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
1162 | if (ret != 0) | 1134 | if (ret != 0) |
1163 | break; | 1135 | return ret; |
1164 | } | 1136 | } |
1165 | return ret; | 1137 | return 0; |
1166 | } | 1138 | } |
1167 | #endif | 1139 | #endif |
1168 | 1140 | ||
@@ -1321,8 +1293,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1321 | /* Decrease module usage counts and free resource */ | 1293 | /* Decrease module usage counts and free resource */ |
1322 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1294 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
1323 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) | 1295 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
1324 | if (cleanup_entry(iter, net, NULL) != 0) | 1296 | cleanup_entry(iter, net); |
1325 | break; | ||
1326 | 1297 | ||
1327 | xt_free_table_info(oldinfo); | 1298 | xt_free_table_info(oldinfo); |
1328 | if (copy_to_user(counters_ptr, counters, | 1299 | if (copy_to_user(counters_ptr, counters, |
@@ -1385,26 +1356,12 @@ do_replace(struct net *net, const void __user *user, unsigned int len) | |||
1385 | 1356 | ||
1386 | free_newinfo_untrans: | 1357 | free_newinfo_untrans: |
1387 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) | 1358 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1388 | if (cleanup_entry(iter, net, NULL) != 0) | 1359 | cleanup_entry(iter, net); |
1389 | break; | ||
1390 | free_newinfo: | 1360 | free_newinfo: |
1391 | xt_free_table_info(newinfo); | 1361 | xt_free_table_info(newinfo); |
1392 | return ret; | 1362 | return ret; |
1393 | } | 1363 | } |
1394 | 1364 | ||
1395 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1396 | * and everything is OK. */ | ||
1397 | static int | ||
1398 | add_counter_to_entry(struct ip6t_entry *e, | ||
1399 | const struct xt_counters addme[], | ||
1400 | unsigned int *i) | ||
1401 | { | ||
1402 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1403 | |||
1404 | (*i)++; | ||
1405 | return 0; | ||
1406 | } | ||
1407 | |||
1408 | static int | 1365 | static int |
1409 | do_add_counters(struct net *net, const void __user *user, unsigned int len, | 1366 | do_add_counters(struct net *net, const void __user *user, unsigned int len, |
1410 | int compat) | 1367 | int compat) |
@@ -1479,9 +1436,10 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
1479 | curcpu = smp_processor_id(); | 1436 | curcpu = smp_processor_id(); |
1480 | xt_info_wrlock(curcpu); | 1437 | xt_info_wrlock(curcpu); |
1481 | loc_cpu_entry = private->entries[curcpu]; | 1438 | loc_cpu_entry = private->entries[curcpu]; |
1482 | xt_entry_foreach(iter, loc_cpu_entry, private->size) | 1439 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1483 | if (add_counter_to_entry(iter, paddc, &i) != 0) | 1440 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1484 | break; | 1441 | ++i; |
1442 | } | ||
1485 | xt_info_wrunlock(curcpu); | 1443 | xt_info_wrunlock(curcpu); |
1486 | 1444 | ||
1487 | unlock_up_free: | 1445 | unlock_up_free: |
@@ -1510,7 +1468,7 @@ struct compat_ip6t_replace { | |||
1510 | static int | 1468 | static int |
1511 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | 1469 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, |
1512 | unsigned int *size, struct xt_counters *counters, | 1470 | unsigned int *size, struct xt_counters *counters, |
1513 | unsigned int *i) | 1471 | unsigned int i) |
1514 | { | 1472 | { |
1515 | struct ip6t_entry_target *t; | 1473 | struct ip6t_entry_target *t; |
1516 | struct compat_ip6t_entry __user *ce; | 1474 | struct compat_ip6t_entry __user *ce; |
@@ -1518,14 +1476,12 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | |||
1518 | compat_uint_t origsize; | 1476 | compat_uint_t origsize; |
1519 | int ret; | 1477 | int ret; |
1520 | 1478 | ||
1521 | ret = -EFAULT; | ||
1522 | origsize = *size; | 1479 | origsize = *size; |
1523 | ce = (struct compat_ip6t_entry __user *)*dstptr; | 1480 | ce = (struct compat_ip6t_entry __user *)*dstptr; |
1524 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry))) | 1481 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || |
1525 | goto out; | 1482 | copy_to_user(&ce->counters, &counters[i], |
1526 | 1483 | sizeof(counters[i])) != 0) | |
1527 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1484 | return -EFAULT; |
1528 | goto out; | ||
1529 | 1485 | ||
1530 | *dstptr += sizeof(struct compat_ip6t_entry); | 1486 | *dstptr += sizeof(struct compat_ip6t_entry); |
1531 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1487 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
@@ -1533,22 +1489,16 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | |||
1533 | ret = IP6T_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); | 1489 | ret = IP6T_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); |
1534 | target_offset = e->target_offset - (origsize - *size); | 1490 | target_offset = e->target_offset - (origsize - *size); |
1535 | if (ret) | 1491 | if (ret) |
1536 | goto out; | 1492 | return ret; |
1537 | t = ip6t_get_target(e); | 1493 | t = ip6t_get_target(e); |
1538 | ret = xt_compat_target_to_user(t, dstptr, size); | 1494 | ret = xt_compat_target_to_user(t, dstptr, size); |
1539 | if (ret) | 1495 | if (ret) |
1540 | goto out; | 1496 | return ret; |
1541 | ret = -EFAULT; | ||
1542 | next_offset = e->next_offset - (origsize - *size); | 1497 | next_offset = e->next_offset - (origsize - *size); |
1543 | if (put_user(target_offset, &ce->target_offset)) | 1498 | if (put_user(target_offset, &ce->target_offset) != 0 || |
1544 | goto out; | 1499 | put_user(next_offset, &ce->next_offset) != 0) |
1545 | if (put_user(next_offset, &ce->next_offset)) | 1500 | return -EFAULT; |
1546 | goto out; | ||
1547 | |||
1548 | (*i)++; | ||
1549 | return 0; | 1501 | return 0; |
1550 | out: | ||
1551 | return ret; | ||
1552 | } | 1502 | } |
1553 | 1503 | ||
1554 | static int | 1504 | static int |
@@ -1585,19 +1535,14 @@ compat_release_match(struct ip6t_entry_match *m, unsigned int *i) | |||
1585 | return 0; | 1535 | return 0; |
1586 | } | 1536 | } |
1587 | 1537 | ||
1588 | static int | 1538 | static void compat_release_entry(struct compat_ip6t_entry *e) |
1589 | compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i) | ||
1590 | { | 1539 | { |
1591 | struct ip6t_entry_target *t; | 1540 | struct ip6t_entry_target *t; |
1592 | 1541 | ||
1593 | if (i && (*i)-- == 0) | ||
1594 | return 1; | ||
1595 | |||
1596 | /* Cleanup all matches */ | 1542 | /* Cleanup all matches */ |
1597 | COMPAT_IP6T_MATCH_ITERATE(e, compat_release_match, NULL); | 1543 | COMPAT_IP6T_MATCH_ITERATE(e, compat_release_match, NULL); |
1598 | t = compat_ip6t_get_target(e); | 1544 | t = compat_ip6t_get_target(e); |
1599 | module_put(t->u.kernel.target->me); | 1545 | module_put(t->u.kernel.target->me); |
1600 | return 0; | ||
1601 | } | 1546 | } |
1602 | 1547 | ||
1603 | static int | 1548 | static int |
@@ -1608,7 +1553,6 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1608 | const unsigned char *limit, | 1553 | const unsigned char *limit, |
1609 | const unsigned int *hook_entries, | 1554 | const unsigned int *hook_entries, |
1610 | const unsigned int *underflows, | 1555 | const unsigned int *underflows, |
1611 | unsigned int *i, | ||
1612 | const char *name) | 1556 | const char *name) |
1613 | { | 1557 | { |
1614 | struct ip6t_entry_target *t; | 1558 | struct ip6t_entry_target *t; |
@@ -1674,8 +1618,6 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1674 | /* Clear counters and comefrom */ | 1618 | /* Clear counters and comefrom */ |
1675 | memset(&e->counters, 0, sizeof(e->counters)); | 1619 | memset(&e->counters, 0, sizeof(e->counters)); |
1676 | e->comefrom = 0; | 1620 | e->comefrom = 0; |
1677 | |||
1678 | (*i)++; | ||
1679 | return 0; | 1621 | return 0; |
1680 | 1622 | ||
1681 | out: | 1623 | out: |
@@ -1725,7 +1667,7 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1725 | } | 1667 | } |
1726 | 1668 | ||
1727 | static int compat_check_entry(struct ip6t_entry *e, struct net *net, | 1669 | static int compat_check_entry(struct ip6t_entry *e, struct net *net, |
1728 | const char *name, unsigned int *i) | 1670 | const char *name) |
1729 | { | 1671 | { |
1730 | unsigned int j; | 1672 | unsigned int j; |
1731 | int ret; | 1673 | int ret; |
@@ -1744,8 +1686,6 @@ static int compat_check_entry(struct ip6t_entry *e, struct net *net, | |||
1744 | ret = check_target(e, net, name); | 1686 | ret = check_target(e, net, name); |
1745 | if (ret) | 1687 | if (ret) |
1746 | goto cleanup_matches; | 1688 | goto cleanup_matches; |
1747 | |||
1748 | (*i)++; | ||
1749 | return 0; | 1689 | return 0; |
1750 | 1690 | ||
1751 | cleanup_matches: | 1691 | cleanup_matches: |
@@ -1790,12 +1730,11 @@ translate_compat_table(struct net *net, | |||
1790 | xt_entry_foreach(iter0, entry0, total_size) { | 1730 | xt_entry_foreach(iter0, entry0, total_size) { |
1791 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, | 1731 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
1792 | entry0, entry0 + total_size, hook_entries, underflows, | 1732 | entry0, entry0 + total_size, hook_entries, underflows, |
1793 | &j, name); | 1733 | name); |
1794 | if (ret != 0) | 1734 | if (ret != 0) |
1795 | break; | 1735 | goto out_unlock; |
1736 | ++j; | ||
1796 | } | 1737 | } |
1797 | if (ret != 0) | ||
1798 | goto out_unlock; | ||
1799 | 1738 | ||
1800 | ret = -EINVAL; | 1739 | ret = -EINVAL; |
1801 | if (j != number) { | 1740 | if (j != number) { |
@@ -1851,9 +1790,10 @@ translate_compat_table(struct net *net, | |||
1851 | 1790 | ||
1852 | i = 0; | 1791 | i = 0; |
1853 | xt_entry_foreach(iter1, entry1, newinfo->size) { | 1792 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1854 | ret = compat_check_entry(iter1, net, name, &i); | 1793 | ret = compat_check_entry(iter1, net, name); |
1855 | if (ret != 0) | 1794 | if (ret != 0) |
1856 | break; | 1795 | break; |
1796 | ++i; | ||
1857 | } | 1797 | } |
1858 | if (ret) { | 1798 | if (ret) { |
1859 | /* | 1799 | /* |
@@ -1866,12 +1806,15 @@ translate_compat_table(struct net *net, | |||
1866 | xt_entry_foreach(iter0, entry0, newinfo->size) { | 1806 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
1867 | if (skip-- > 0) | 1807 | if (skip-- > 0) |
1868 | continue; | 1808 | continue; |
1869 | if (compat_release_entry(iter0, &j) != 0) | 1809 | if (j-- == 0) |
1870 | break; | 1810 | break; |
1811 | compat_release_entry(iter0); | ||
1871 | } | 1812 | } |
1872 | xt_entry_foreach(iter1, entry1, newinfo->size) | 1813 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1873 | if (cleanup_entry(iter1, net, &i) != 0) | 1814 | if (i-- == 0) |
1874 | break; | 1815 | break; |
1816 | cleanup_entry(iter1, net); | ||
1817 | } | ||
1875 | xt_free_table_info(newinfo); | 1818 | xt_free_table_info(newinfo); |
1876 | return ret; | 1819 | return ret; |
1877 | } | 1820 | } |
@@ -1889,9 +1832,11 @@ translate_compat_table(struct net *net, | |||
1889 | free_newinfo: | 1832 | free_newinfo: |
1890 | xt_free_table_info(newinfo); | 1833 | xt_free_table_info(newinfo); |
1891 | out: | 1834 | out: |
1892 | xt_entry_foreach(iter0, entry0, total_size) | 1835 | xt_entry_foreach(iter0, entry0, total_size) { |
1893 | if (compat_release_entry(iter0, &j) != 0) | 1836 | if (j-- == 0) |
1894 | break; | 1837 | break; |
1838 | compat_release_entry(iter0); | ||
1839 | } | ||
1895 | return ret; | 1840 | return ret; |
1896 | out_unlock: | 1841 | out_unlock: |
1897 | xt_compat_flush_offsets(AF_INET6); | 1842 | xt_compat_flush_offsets(AF_INET6); |
@@ -1946,8 +1891,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1946 | 1891 | ||
1947 | free_newinfo_untrans: | 1892 | free_newinfo_untrans: |
1948 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) | 1893 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1949 | if (cleanup_entry(iter, net, NULL) != 0) | 1894 | cleanup_entry(iter, net); |
1950 | break; | ||
1951 | free_newinfo: | 1895 | free_newinfo: |
1952 | xt_free_table_info(newinfo); | 1896 | xt_free_table_info(newinfo); |
1953 | return ret; | 1897 | return ret; |
@@ -2011,7 +1955,7 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
2011 | size = total_size; | 1955 | size = total_size; |
2012 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { | 1956 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
2013 | ret = compat_copy_entry_to_user(iter, &pos, | 1957 | ret = compat_copy_entry_to_user(iter, &pos, |
2014 | &size, counters, &i); | 1958 | &size, counters, i++); |
2015 | if (ret != 0) | 1959 | if (ret != 0) |
2016 | break; | 1960 | break; |
2017 | } | 1961 | } |
@@ -2221,8 +2165,7 @@ void ip6t_unregister_table(struct net *net, struct xt_table *table) | |||
2221 | /* Decrease module usage counts and free resources */ | 2165 | /* Decrease module usage counts and free resources */ |
2222 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 2166 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
2223 | xt_entry_foreach(iter, loc_cpu_entry, private->size) | 2167 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
2224 | if (cleanup_entry(iter, net, NULL) != 0) | 2168 | cleanup_entry(iter, net); |
2225 | break; | ||
2226 | if (private->number > private->initial_entries) | 2169 | if (private->number > private->initial_entries) |
2227 | module_put(table_owner); | 2170 | module_put(table_owner); |
2228 | xt_free_table_info(private); | 2171 | xt_free_table_info(private); |