Loading include/linux/netfilter/x_tables.h +17 −0 Original line number Original line Diff line number Diff line Loading @@ -120,6 +120,7 @@ struct xt_counters_info { #define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */ #define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */ #ifndef __KERNEL__ /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define XT_MATCH_ITERATE(type, e, fn, args...) \ #define XT_MATCH_ITERATE(type, e, fn, args...) \ ({ \ ({ \ Loading Loading @@ -163,6 +164,22 @@ struct xt_counters_info { #define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ #define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) #endif /* !__KERNEL__ */ /* pos is normally a struct ipt_entry/ip6t_entry/etc. */ #define xt_entry_foreach(pos, ehead, esize) \ for ((pos) = (typeof(pos))(ehead); \ (pos) < (typeof(pos))((char *)(ehead) + (esize)); \ (pos) = (typeof(pos))((char *)(pos) + (pos)->next_offset)) /* can only be xt_entry_match, so no use of typeof here */ #define xt_ematch_foreach(pos, entry) \ for ((pos) = (struct xt_entry_match *)entry->elems; \ (pos) < (struct xt_entry_match *)((char *)(entry) + \ (entry)->target_offset); \ (pos) = (struct xt_entry_match *)((char *)(pos) + \ (pos)->u.match_size)) #ifdef __KERNEL__ #ifdef __KERNEL__ #include <linux/netdevice.h> #include <linux/netdevice.h> Loading include/linux/netfilter_arp/arp_tables.h +2 −8 Original line number Original line Diff line number Diff line Loading @@ -211,9 +211,11 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e return (void *)e + e->target_offset; return (void *)e + e->target_offset; } } #ifndef __KERNEL__ /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ #define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args) XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args) #endif /* /* * Main firewall chains definitions and global var's definitions. * Main firewall chains definitions and global var's definitions. Loading Loading @@ -291,14 +293,6 @@ compat_arpt_get_target(struct compat_arpt_entry *e) #define COMPAT_ARPT_ALIGN(s) COMPAT_XT_ALIGN(s) #define COMPAT_ARPT_ALIGN(s) COMPAT_XT_ALIGN(s) /* fn returns 0 to continue iteration */ #define COMPAT_ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct compat_arpt_entry, entries, size, fn, ## args) #define COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ XT_ENTRY_ITERATE_CONTINUE(struct compat_arpt_entry, entries, size, n, \ fn, ## args) #endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */ #endif /*__KERNEL__*/ #endif /*__KERNEL__*/ #endif /* _ARPTABLES_H */ #endif /* _ARPTABLES_H */ include/linux/netfilter_ipv4/ip_tables.h +2 −13 Original line number Original line Diff line number Diff line Loading @@ -223,6 +223,7 @@ ipt_get_target(struct ipt_entry *e) return (void *)e + e->target_offset; return (void *)e + e->target_offset; } } #ifndef __KERNEL__ /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define IPT_MATCH_ITERATE(e, fn, args...) \ #define IPT_MATCH_ITERATE(e, fn, args...) \ XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args) XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args) Loading @@ -230,6 +231,7 @@ ipt_get_target(struct ipt_entry *e) /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define IPT_ENTRY_ITERATE(entries, size, fn, args...) \ #define IPT_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args) XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args) #endif /* /* * Main firewall chains definitions and global var's definitions. * Main firewall chains definitions and global var's definitions. Loading Loading @@ -313,19 +315,6 @@ compat_ipt_get_target(struct compat_ipt_entry *e) #define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s) #define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s) /* fn returns 0 to continue iteration */ #define COMPAT_IPT_MATCH_ITERATE(e, fn, args...) \ XT_MATCH_ITERATE(struct compat_ipt_entry, e, fn, ## args) /* fn returns 0 to continue iteration */ #define COMPAT_IPT_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct compat_ipt_entry, entries, size, fn, ## args) /* fn returns 0 to continue iteration */ #define COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ XT_ENTRY_ITERATE_CONTINUE(struct compat_ipt_entry, entries, size, n, \ fn, ## args) #endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */ #endif /*__KERNEL__*/ #endif /*__KERNEL__*/ #endif /* _IPTABLES_H */ #endif /* _IPTABLES_H */ include/linux/netfilter_ipv6/ip6_tables.h +2 −12 Original line number Original line Diff line number Diff line Loading @@ -280,6 +280,7 @@ ip6t_get_target(struct ip6t_entry *e) return (void *)e + e->target_offset; return (void *)e + e->target_offset; } } #ifndef __KERNEL__ /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define IP6T_MATCH_ITERATE(e, fn, args...) \ #define IP6T_MATCH_ITERATE(e, fn, args...) \ XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args) XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args) Loading @@ -287,6 +288,7 @@ ip6t_get_target(struct ip6t_entry *e) /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ #define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args) XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args) #endif /* /* * Main firewall chains definitions and global var's definitions. * Main firewall chains definitions and global var's definitions. Loading Loading @@ -341,18 +343,6 @@ compat_ip6t_get_target(struct compat_ip6t_entry *e) #define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s) #define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s) /* fn returns 0 to continue iteration */ #define COMPAT_IP6T_MATCH_ITERATE(e, fn, args...) \ XT_MATCH_ITERATE(struct compat_ip6t_entry, e, fn, ## args) /* fn returns 0 to continue iteration */ #define COMPAT_IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct compat_ip6t_entry, entries, size, fn, ## args) #define COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ XT_ENTRY_ITERATE_CONTINUE(struct compat_ip6t_entry, entries, size, n, \ fn, ## args) #endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */ #endif /*__KERNEL__*/ #endif /*__KERNEL__*/ #endif /* _IP6_TABLES_H */ #endif /* _IP6_TABLES_H */ net/ipv4/netfilter/arp_tables.c +135 −166 Original line number Original line Diff line number Diff line Loading @@ -512,8 +512,7 @@ static inline int check_target(struct arpt_entry *e, const char *name) } } static inline int static inline int find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) unsigned int *i) { { struct arpt_entry_target *t; struct arpt_entry_target *t; struct xt_target *target; struct xt_target *target; Loading @@ -538,8 +537,6 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, ret = check_target(e, name); ret = check_target(e, name); if (ret) if (ret) goto err; goto err; (*i)++; return 0; return 0; err: err: module_put(t->u.kernel.target->me); module_put(t->u.kernel.target->me); Loading Loading @@ -568,8 +565,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, const unsigned char *limit, const unsigned char *limit, const unsigned int *hook_entries, const unsigned int *hook_entries, const unsigned int *underflows, const unsigned int *underflows, unsigned int valid_hooks, unsigned int valid_hooks) unsigned int *i) { { unsigned int h; unsigned int h; Loading Loading @@ -606,19 +602,14 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, /* Clear counters and comefrom */ /* Clear counters and comefrom */ e->counters = ((struct xt_counters) { 0, 0 }); e->counters = ((struct xt_counters) { 0, 0 }); e->comefrom = 0; e->comefrom = 0; (*i)++; return 0; return 0; } } static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) static inline void cleanup_entry(struct arpt_entry *e) { { struct xt_tgdtor_param par; struct xt_tgdtor_param par; struct arpt_entry_target *t; struct arpt_entry_target *t; if (i && (*i)-- == 0) return 1; t = arpt_get_target(e); t = arpt_get_target(e); par.target = t->u.kernel.target; par.target = t->u.kernel.target; par.targinfo = t->data; par.targinfo = t->data; Loading @@ -626,26 +617,20 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) if (par.target->destroy != NULL) if (par.target->destroy != NULL) par.target->destroy(&par); par.target->destroy(&par); module_put(par.target->me); module_put(par.target->me); return 0; } } /* Checks and translates the user-supplied table segment (held in /* Checks and translates the user-supplied table segment (held in * newinfo). * newinfo). */ */ static int translate_table(const char *name, static int translate_table(struct xt_table_info *newinfo, void *entry0, unsigned int valid_hooks, const struct arpt_replace *repl) struct xt_table_info *newinfo, void *entry0, unsigned int size, unsigned int number, const unsigned int *hook_entries, const unsigned int *underflows) { { struct arpt_entry *iter; unsigned int i; unsigned int i; int ret; int ret = 0; newinfo->size = size; newinfo->size = repl->size; newinfo->number = number; newinfo->number = repl->num_entries; /* Init all hooks to impossible value. */ /* Init all hooks to impossible value. */ for (i = 0; i < NF_ARP_NUMHOOKS; i++) { for (i = 0; i < NF_ARP_NUMHOOKS; i++) { Loading @@ -657,52 +642,61 @@ static int translate_table(const char *name, i = 0; i = 0; /* Walk through entries, checking offsets. */ /* Walk through entries, checking offsets. */ ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, xt_entry_foreach(iter, entry0, newinfo->size) { check_entry_size_and_hooks, ret = check_entry_size_and_hooks(iter, newinfo, entry0, newinfo, entry0 + repl->size, repl->hook_entry, repl->underflow, entry0, repl->valid_hooks); entry0 + size, if (ret != 0) hook_entries, underflows, valid_hooks, &i); break; ++i; } duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); if (ret != 0) if (ret != 0) return ret; return ret; if (i != number) { if (i != repl->num_entries) { duprintf("translate_table: %u not %u entries\n", duprintf("translate_table: %u not %u entries\n", i, number); i, repl->num_entries); return -EINVAL; return -EINVAL; } } /* Check hooks all assigned */ /* Check hooks all assigned */ for (i = 0; i < NF_ARP_NUMHOOKS; i++) { for (i = 0; i < NF_ARP_NUMHOOKS; i++) { /* Only hooks which are valid */ /* Only hooks which are valid */ if (!(valid_hooks & (1 << i))) if (!(repl->valid_hooks & (1 << i))) continue; continue; if (newinfo->hook_entry[i] == 0xFFFFFFFF) { if (newinfo->hook_entry[i] == 0xFFFFFFFF) { duprintf("Invalid hook entry %u %u\n", duprintf("Invalid hook entry %u %u\n", i, hook_entries[i]); i, repl->hook_entry[i]); return -EINVAL; return -EINVAL; } } if (newinfo->underflow[i] == 0xFFFFFFFF) { if (newinfo->underflow[i] == 0xFFFFFFFF) { duprintf("Invalid underflow %u %u\n", duprintf("Invalid underflow %u %u\n", i, underflows[i]); i, repl->underflow[i]); return -EINVAL; return -EINVAL; } } } } if (!mark_source_chains(newinfo, valid_hooks, entry0)) { if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) { duprintf("Looping hook\n"); duprintf("Looping hook\n"); return -ELOOP; return -ELOOP; } } /* Finally, each sanity check must pass */ /* Finally, each sanity check must pass */ i = 0; i = 0; ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, xt_entry_foreach(iter, entry0, newinfo->size) { find_check_entry, name, size, &i); ret = find_check_entry(iter, repl->name, repl->size); if (ret != 0) break; ++i; } if (ret != 0) { if (ret != 0) { ARPT_ENTRY_ITERATE(entry0, newinfo->size, xt_entry_foreach(iter, entry0, newinfo->size) { cleanup_entry, &i); if (i-- == 0) break; cleanup_entry(iter); } return ret; return ret; } } Loading @@ -715,30 +709,10 @@ static int translate_table(const char *name, return ret; return ret; } } /* Gets counters. */ static inline int add_entry_to_counter(const struct arpt_entry *e, struct xt_counters total[], unsigned int *i) { ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); (*i)++; return 0; } static inline int set_entry_to_counter(const struct arpt_entry *e, struct xt_counters total[], unsigned int *i) { SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); (*i)++; return 0; } static void get_counters(const struct xt_table_info *t, static void get_counters(const struct xt_table_info *t, struct xt_counters counters[]) struct xt_counters counters[]) { { struct arpt_entry *iter; unsigned int cpu; unsigned int cpu; unsigned int i; unsigned int i; unsigned int curcpu; unsigned int curcpu; Loading @@ -754,22 +728,22 @@ static void get_counters(const struct xt_table_info *t, curcpu = smp_processor_id(); curcpu = smp_processor_id(); i = 0; i = 0; ARPT_ENTRY_ITERATE(t->entries[curcpu], xt_entry_foreach(iter, t->entries[curcpu], t->size) { t->size, SET_COUNTER(counters[i], iter->counters.bcnt, set_entry_to_counter, iter->counters.pcnt); counters, ++i; &i); } for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) { if (cpu == curcpu) if (cpu == curcpu) continue; continue; i = 0; i = 0; xt_info_wrlock(cpu); xt_info_wrlock(cpu); ARPT_ENTRY_ITERATE(t->entries[cpu], xt_entry_foreach(iter, t->entries[cpu], t->size) { t->size, ADD_COUNTER(counters[i], iter->counters.bcnt, add_entry_to_counter, iter->counters.pcnt); counters, ++i; &i); } xt_info_wrunlock(cpu); xt_info_wrunlock(cpu); } } local_bh_enable(); local_bh_enable(); Loading Loading @@ -899,7 +873,9 @@ static int compat_calc_entry(const struct arpt_entry *e, static int compat_table_info(const struct xt_table_info *info, static int compat_table_info(const struct xt_table_info *info, struct xt_table_info *newinfo) struct xt_table_info *newinfo) { { struct arpt_entry *iter; void *loc_cpu_entry; void *loc_cpu_entry; int ret; if (!newinfo || !info) if (!newinfo || !info) return -EINVAL; return -EINVAL; Loading @@ -908,9 +884,12 @@ static int compat_table_info(const struct xt_table_info *info, memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); newinfo->initial_entries = 0; newinfo->initial_entries = 0; loc_cpu_entry = info->entries[raw_smp_processor_id()]; loc_cpu_entry = info->entries[raw_smp_processor_id()]; return ARPT_ENTRY_ITERATE(loc_cpu_entry, info->size, xt_entry_foreach(iter, loc_cpu_entry, info->size) { compat_calc_entry, info, loc_cpu_entry, ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); newinfo); if (ret != 0) return ret; } return 0; } } #endif #endif Loading Loading @@ -1025,6 +1004,7 @@ static int __do_replace(struct net *net, const char *name, struct xt_table_info *oldinfo; struct xt_table_info *oldinfo; struct xt_counters *counters; struct xt_counters *counters; void *loc_cpu_old_entry; void *loc_cpu_old_entry; struct arpt_entry *iter; ret = 0; ret = 0; counters = vmalloc_node(num_counters * sizeof(struct xt_counters), counters = vmalloc_node(num_counters * sizeof(struct xt_counters), Loading Loading @@ -1068,8 +1048,8 @@ static int __do_replace(struct net *net, const char *name, /* Decrease module usage counts and free resource */ /* Decrease module usage counts and free resource */ loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) NULL); cleanup_entry(iter); xt_free_table_info(oldinfo); xt_free_table_info(oldinfo); if (copy_to_user(counters_ptr, counters, if (copy_to_user(counters_ptr, counters, Loading @@ -1095,6 +1075,7 @@ static int do_replace(struct net *net, const void __user *user, struct arpt_replace tmp; struct arpt_replace tmp; struct xt_table_info *newinfo; struct xt_table_info *newinfo; void *loc_cpu_entry; void *loc_cpu_entry; struct arpt_entry *iter; if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) return -EFAULT; return -EFAULT; Loading @@ -1115,9 +1096,7 @@ static int do_replace(struct net *net, const void __user *user, goto free_newinfo; goto free_newinfo; } } ret = translate_table(tmp.name, tmp.valid_hooks, ret = translate_table(newinfo, loc_cpu_entry, &tmp); newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, tmp.hook_entry, tmp.underflow); if (ret != 0) if (ret != 0) goto free_newinfo; goto free_newinfo; Loading @@ -1130,25 +1109,13 @@ static int do_replace(struct net *net, const void __user *user, return 0; return 0; free_newinfo_untrans: free_newinfo_untrans: ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) cleanup_entry(iter); free_newinfo: free_newinfo: xt_free_table_info(newinfo); xt_free_table_info(newinfo); return ret; return ret; } } /* We're lazy, and add to the first CPU; overflow works its fey magic * and everything is OK. */ static int add_counter_to_entry(struct arpt_entry *e, const struct xt_counters addme[], unsigned int *i) { ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); (*i)++; return 0; } static int do_add_counters(struct net *net, const void __user *user, static int do_add_counters(struct net *net, const void __user *user, unsigned int len, int compat) unsigned int len, int compat) { { Loading @@ -1163,6 +1130,7 @@ static int do_add_counters(struct net *net, const void __user *user, const struct xt_table_info *private; const struct xt_table_info *private; int ret = 0; int ret = 0; void *loc_cpu_entry; void *loc_cpu_entry; struct arpt_entry *iter; #ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT struct compat_xt_counters_info compat_tmp; struct compat_xt_counters_info compat_tmp; Loading Loading @@ -1220,11 +1188,10 @@ static int do_add_counters(struct net *net, const void __user *user, curcpu = smp_processor_id(); curcpu = smp_processor_id(); loc_cpu_entry = private->entries[curcpu]; loc_cpu_entry = private->entries[curcpu]; xt_info_wrlock(curcpu); xt_info_wrlock(curcpu); ARPT_ENTRY_ITERATE(loc_cpu_entry, xt_entry_foreach(iter, loc_cpu_entry, private->size) { private->size, ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); add_counter_to_entry, ++i; paddc, } &i); xt_info_wrunlock(curcpu); xt_info_wrunlock(curcpu); unlock_up_free: unlock_up_free: local_bh_enable(); local_bh_enable(); Loading @@ -1237,17 +1204,12 @@ static int do_add_counters(struct net *net, const void __user *user, } } #ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT static inline int static inline void compat_release_entry(struct compat_arpt_entry *e) compat_release_entry(struct compat_arpt_entry *e, unsigned int *i) { { struct arpt_entry_target *t; struct arpt_entry_target *t; if (i && (*i)-- == 0) return 1; t = compat_arpt_get_target(e); t = compat_arpt_get_target(e); module_put(t->u.kernel.target->me); module_put(t->u.kernel.target->me); return 0; } } static inline int static inline int Loading @@ -1258,7 +1220,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, const unsigned char *limit, const unsigned char *limit, const unsigned int *hook_entries, const unsigned int *hook_entries, const unsigned int *underflows, const unsigned int *underflows, unsigned int *i, const char *name) const char *name) { { struct arpt_entry_target *t; struct arpt_entry_target *t; Loading Loading @@ -1318,8 +1279,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, /* Clear counters and comefrom */ /* Clear counters and comefrom */ memset(&e->counters, 0, sizeof(e->counters)); memset(&e->counters, 0, sizeof(e->counters)); e->comefrom = 0; e->comefrom = 0; (*i)++; return 0; return 0; release_target: release_target: Loading Loading @@ -1363,19 +1322,6 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, return ret; return ret; } } static inline int compat_check_entry(struct arpt_entry *e, const char *name, unsigned int *i) { int ret; ret = check_target(e, name); if (ret) return ret; (*i)++; return 0; } static int translate_compat_table(const char *name, static int translate_compat_table(const char *name, unsigned int valid_hooks, unsigned int valid_hooks, struct xt_table_info **pinfo, struct xt_table_info **pinfo, Loading @@ -1388,8 +1334,10 @@ static int translate_compat_table(const char *name, unsigned int i, j; unsigned int i, j; struct xt_table_info *newinfo, *info; struct xt_table_info *newinfo, *info; void *pos, *entry0, *entry1; void *pos, *entry0, *entry1; struct compat_arpt_entry *iter0; struct arpt_entry *iter1; unsigned int size; unsigned int size; int ret; int ret = 0; info = *pinfo; info = *pinfo; entry0 = *pentry0; entry0 = *pentry0; Loading @@ -1406,13 +1354,14 @@ static int translate_compat_table(const char *name, j = 0; j = 0; xt_compat_lock(NFPROTO_ARP); xt_compat_lock(NFPROTO_ARP); /* Walk through entries, checking offsets. */ /* Walk through entries, checking offsets. */ ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, xt_entry_foreach(iter0, entry0, total_size) { check_compat_entry_size_and_hooks, ret = check_compat_entry_size_and_hooks(iter0, info, &size, info, &size, entry0, entry0, entry0 + total_size, hook_entries, underflows, entry0 + total_size, name); hook_entries, underflows, &j, name); if (ret != 0) if (ret != 0) goto out_unlock; goto out_unlock; ++j; } ret = -EINVAL; ret = -EINVAL; if (j != number) { if (j != number) { Loading Loading @@ -1451,9 +1400,12 @@ static int translate_compat_table(const char *name, entry1 = newinfo->entries[raw_smp_processor_id()]; entry1 = newinfo->entries[raw_smp_processor_id()]; pos = entry1; pos = entry1; size = total_size; size = total_size; ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, xt_entry_foreach(iter0, entry0, total_size) { compat_copy_entry_from_user, ret = compat_copy_entry_from_user(iter0, &pos, &pos, &size, name, newinfo, entry1); &size, name, newinfo, entry1); if (ret != 0) break; } xt_compat_flush_offsets(NFPROTO_ARP); xt_compat_flush_offsets(NFPROTO_ARP); xt_compat_unlock(NFPROTO_ARP); xt_compat_unlock(NFPROTO_ARP); if (ret) if (ret) Loading @@ -1464,13 +1416,32 @@ static int translate_compat_table(const char *name, goto free_newinfo; goto free_newinfo; i = 0; i = 0; ret = ARPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, xt_entry_foreach(iter1, entry1, newinfo->size) { name, &i); ret = check_target(iter1, name); if (ret != 0) break; ++i; } if (ret) { if (ret) { /* * The first i matches need cleanup_entry (calls ->destroy) * because they had called ->check already. The other j-i * entries need only release. */ int skip = i; j -= i; j -= i; COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, xt_entry_foreach(iter0, entry0, newinfo->size) { compat_release_entry, &j); if (skip-- > 0) ARPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i); continue; if (j-- == 0) break; compat_release_entry(iter0); } xt_entry_foreach(iter1, entry1, newinfo->size) { if (i-- == 0) break; cleanup_entry(iter1); } xt_free_table_info(newinfo); xt_free_table_info(newinfo); return ret; return ret; } } Loading @@ -1488,7 +1459,11 @@ static int translate_compat_table(const char *name, free_newinfo: free_newinfo: xt_free_table_info(newinfo); xt_free_table_info(newinfo); out: out: COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); xt_entry_foreach(iter0, entry0, total_size) { if (j-- == 0) break; compat_release_entry(iter0); } return ret; return ret; out_unlock: out_unlock: xt_compat_flush_offsets(NFPROTO_ARP); xt_compat_flush_offsets(NFPROTO_ARP); Loading @@ -1515,6 +1490,7 @@ static int compat_do_replace(struct net *net, void __user *user, struct compat_arpt_replace tmp; struct compat_arpt_replace tmp; struct xt_table_info *newinfo; struct xt_table_info *newinfo; void *loc_cpu_entry; void *loc_cpu_entry; struct arpt_entry *iter; if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) return -EFAULT; return -EFAULT; Loading Loading @@ -1552,7 +1528,8 @@ static int compat_do_replace(struct net *net, void __user *user, return 0; return 0; free_newinfo_untrans: free_newinfo_untrans: ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) cleanup_entry(iter); free_newinfo: free_newinfo: xt_free_table_info(newinfo); xt_free_table_info(newinfo); return ret; return ret; Loading Loading @@ -1586,7 +1563,7 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, compat_uint_t *size, compat_uint_t *size, struct xt_counters *counters, struct xt_counters *counters, unsigned int *i) unsigned int i) { { struct arpt_entry_target *t; struct arpt_entry_target *t; struct compat_arpt_entry __user *ce; struct compat_arpt_entry __user *ce; Loading @@ -1594,14 +1571,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, compat_uint_t origsize; compat_uint_t origsize; int ret; int ret; ret = -EFAULT; origsize = *size; origsize = *size; ce = (struct compat_arpt_entry __user *)*dstptr; ce = (struct compat_arpt_entry __user *)*dstptr; if (copy_to_user(ce, e, sizeof(struct arpt_entry))) if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || goto out; copy_to_user(&ce->counters, &counters[i], sizeof(counters[i])) != 0) if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) return -EFAULT; goto out; *dstptr += sizeof(struct compat_arpt_entry); *dstptr += sizeof(struct compat_arpt_entry); *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); Loading @@ -1611,18 +1586,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, t = arpt_get_target(e); t = arpt_get_target(e); ret = xt_compat_target_to_user(t, dstptr, size); ret = xt_compat_target_to_user(t, dstptr, size); if (ret) if (ret) goto out; return ret; ret = -EFAULT; next_offset = e->next_offset - (origsize - *size); next_offset = e->next_offset - (origsize - *size); if (put_user(target_offset, &ce->target_offset)) if (put_user(target_offset, &ce->target_offset) != 0 || goto out; put_user(next_offset, &ce->next_offset) != 0) if (put_user(next_offset, &ce->next_offset)) return -EFAULT; goto out; (*i)++; return 0; return 0; out: return ret; } } static int compat_copy_entries_to_user(unsigned int total_size, static int compat_copy_entries_to_user(unsigned int total_size, Loading @@ -1636,6 +1605,7 @@ static int compat_copy_entries_to_user(unsigned int total_size, int ret = 0; int ret = 0; void *loc_cpu_entry; void *loc_cpu_entry; unsigned int i = 0; unsigned int i = 0; struct arpt_entry *iter; counters = alloc_counters(table); counters = alloc_counters(table); if (IS_ERR(counters)) if (IS_ERR(counters)) Loading @@ -1645,9 +1615,12 @@ static int compat_copy_entries_to_user(unsigned int total_size, loc_cpu_entry = private->entries[raw_smp_processor_id()]; loc_cpu_entry = private->entries[raw_smp_processor_id()]; pos = userptr; pos = userptr; size = total_size; size = total_size; ret = ARPT_ENTRY_ITERATE(loc_cpu_entry, total_size, xt_entry_foreach(iter, loc_cpu_entry, total_size) { compat_copy_entry_to_user, ret = compat_copy_entry_to_user(iter, &pos, &pos, &size, counters, &i); &size, counters, i++); if (ret != 0) break; } vfree(counters); vfree(counters); return ret; return ret; } } Loading Loading @@ -1815,12 +1788,7 @@ struct xt_table *arpt_register_table(struct net *net, loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; memcpy(loc_cpu_entry, repl->entries, repl->size); memcpy(loc_cpu_entry, repl->entries, repl->size); ret = translate_table(table->name, table->valid_hooks, ret = translate_table(newinfo, loc_cpu_entry, repl); newinfo, loc_cpu_entry, repl->size, repl->num_entries, repl->hook_entry, repl->underflow); duprintf("arpt_register_table: translate table gives %d\n", ret); duprintf("arpt_register_table: translate table gives %d\n", ret); if (ret != 0) if (ret != 0) goto out_free; goto out_free; Loading @@ -1843,13 +1811,14 @@ void arpt_unregister_table(struct xt_table *table) struct xt_table_info *private; struct xt_table_info *private; void *loc_cpu_entry; void *loc_cpu_entry; struct module *table_owner = table->me; struct module *table_owner = table->me; struct arpt_entry *iter; private = xt_unregister_table(table); private = xt_unregister_table(table); /* Decrease module usage counts and free resources */ /* Decrease module usage counts and free resources */ loc_cpu_entry = private->entries[raw_smp_processor_id()]; loc_cpu_entry = private->entries[raw_smp_processor_id()]; ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size, xt_entry_foreach(iter, loc_cpu_entry, private->size) cleanup_entry, NULL); cleanup_entry(iter); if (private->number > private->initial_entries) if (private->number > private->initial_entries) module_put(table_owner); module_put(table_owner); xt_free_table_info(private); xt_free_table_info(private); Loading Loading
include/linux/netfilter/x_tables.h +17 −0 Original line number Original line Diff line number Diff line Loading @@ -120,6 +120,7 @@ struct xt_counters_info { #define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */ #define XT_INV_PROTO 0x40 /* Invert the sense of PROTO. */ #ifndef __KERNEL__ /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define XT_MATCH_ITERATE(type, e, fn, args...) \ #define XT_MATCH_ITERATE(type, e, fn, args...) \ ({ \ ({ \ Loading Loading @@ -163,6 +164,22 @@ struct xt_counters_info { #define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ #define XT_ENTRY_ITERATE(type, entries, size, fn, args...) \ XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) XT_ENTRY_ITERATE_CONTINUE(type, entries, size, 0, fn, args) #endif /* !__KERNEL__ */ /* pos is normally a struct ipt_entry/ip6t_entry/etc. */ #define xt_entry_foreach(pos, ehead, esize) \ for ((pos) = (typeof(pos))(ehead); \ (pos) < (typeof(pos))((char *)(ehead) + (esize)); \ (pos) = (typeof(pos))((char *)(pos) + (pos)->next_offset)) /* can only be xt_entry_match, so no use of typeof here */ #define xt_ematch_foreach(pos, entry) \ for ((pos) = (struct xt_entry_match *)entry->elems; \ (pos) < (struct xt_entry_match *)((char *)(entry) + \ (entry)->target_offset); \ (pos) = (struct xt_entry_match *)((char *)(pos) + \ (pos)->u.match_size)) #ifdef __KERNEL__ #ifdef __KERNEL__ #include <linux/netdevice.h> #include <linux/netdevice.h> Loading
include/linux/netfilter_arp/arp_tables.h +2 −8 Original line number Original line Diff line number Diff line Loading @@ -211,9 +211,11 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e return (void *)e + e->target_offset; return (void *)e + e->target_offset; } } #ifndef __KERNEL__ /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ #define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args) XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args) #endif /* /* * Main firewall chains definitions and global var's definitions. * Main firewall chains definitions and global var's definitions. Loading Loading @@ -291,14 +293,6 @@ compat_arpt_get_target(struct compat_arpt_entry *e) #define COMPAT_ARPT_ALIGN(s) COMPAT_XT_ALIGN(s) #define COMPAT_ARPT_ALIGN(s) COMPAT_XT_ALIGN(s) /* fn returns 0 to continue iteration */ #define COMPAT_ARPT_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct compat_arpt_entry, entries, size, fn, ## args) #define COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ XT_ENTRY_ITERATE_CONTINUE(struct compat_arpt_entry, entries, size, n, \ fn, ## args) #endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */ #endif /*__KERNEL__*/ #endif /*__KERNEL__*/ #endif /* _ARPTABLES_H */ #endif /* _ARPTABLES_H */
include/linux/netfilter_ipv4/ip_tables.h +2 −13 Original line number Original line Diff line number Diff line Loading @@ -223,6 +223,7 @@ ipt_get_target(struct ipt_entry *e) return (void *)e + e->target_offset; return (void *)e + e->target_offset; } } #ifndef __KERNEL__ /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define IPT_MATCH_ITERATE(e, fn, args...) \ #define IPT_MATCH_ITERATE(e, fn, args...) \ XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args) XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args) Loading @@ -230,6 +231,7 @@ ipt_get_target(struct ipt_entry *e) /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define IPT_ENTRY_ITERATE(entries, size, fn, args...) \ #define IPT_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args) XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args) #endif /* /* * Main firewall chains definitions and global var's definitions. * Main firewall chains definitions and global var's definitions. Loading Loading @@ -313,19 +315,6 @@ compat_ipt_get_target(struct compat_ipt_entry *e) #define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s) #define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s) /* fn returns 0 to continue iteration */ #define COMPAT_IPT_MATCH_ITERATE(e, fn, args...) \ XT_MATCH_ITERATE(struct compat_ipt_entry, e, fn, ## args) /* fn returns 0 to continue iteration */ #define COMPAT_IPT_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct compat_ipt_entry, entries, size, fn, ## args) /* fn returns 0 to continue iteration */ #define COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ XT_ENTRY_ITERATE_CONTINUE(struct compat_ipt_entry, entries, size, n, \ fn, ## args) #endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */ #endif /*__KERNEL__*/ #endif /*__KERNEL__*/ #endif /* _IPTABLES_H */ #endif /* _IPTABLES_H */
include/linux/netfilter_ipv6/ip6_tables.h +2 −12 Original line number Original line Diff line number Diff line Loading @@ -280,6 +280,7 @@ ip6t_get_target(struct ip6t_entry *e) return (void *)e + e->target_offset; return (void *)e + e->target_offset; } } #ifndef __KERNEL__ /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define IP6T_MATCH_ITERATE(e, fn, args...) \ #define IP6T_MATCH_ITERATE(e, fn, args...) \ XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args) XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args) Loading @@ -287,6 +288,7 @@ ip6t_get_target(struct ip6t_entry *e) /* fn returns 0 to continue iteration */ /* fn returns 0 to continue iteration */ #define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ #define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args) XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args) #endif /* /* * Main firewall chains definitions and global var's definitions. * Main firewall chains definitions and global var's definitions. Loading Loading @@ -341,18 +343,6 @@ compat_ip6t_get_target(struct compat_ip6t_entry *e) #define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s) #define COMPAT_IP6T_ALIGN(s) COMPAT_XT_ALIGN(s) /* fn returns 0 to continue iteration */ #define COMPAT_IP6T_MATCH_ITERATE(e, fn, args...) \ XT_MATCH_ITERATE(struct compat_ip6t_entry, e, fn, ## args) /* fn returns 0 to continue iteration */ #define COMPAT_IP6T_ENTRY_ITERATE(entries, size, fn, args...) \ XT_ENTRY_ITERATE(struct compat_ip6t_entry, entries, size, fn, ## args) #define COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entries, size, n, fn, args...) \ XT_ENTRY_ITERATE_CONTINUE(struct compat_ip6t_entry, entries, size, n, \ fn, ## args) #endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */ #endif /*__KERNEL__*/ #endif /*__KERNEL__*/ #endif /* _IP6_TABLES_H */ #endif /* _IP6_TABLES_H */
net/ipv4/netfilter/arp_tables.c +135 −166 Original line number Original line Diff line number Diff line Loading @@ -512,8 +512,7 @@ static inline int check_target(struct arpt_entry *e, const char *name) } } static inline int static inline int find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) unsigned int *i) { { struct arpt_entry_target *t; struct arpt_entry_target *t; struct xt_target *target; struct xt_target *target; Loading @@ -538,8 +537,6 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, ret = check_target(e, name); ret = check_target(e, name); if (ret) if (ret) goto err; goto err; (*i)++; return 0; return 0; err: err: module_put(t->u.kernel.target->me); module_put(t->u.kernel.target->me); Loading Loading @@ -568,8 +565,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, const unsigned char *limit, const unsigned char *limit, const unsigned int *hook_entries, const unsigned int *hook_entries, const unsigned int *underflows, const unsigned int *underflows, unsigned int valid_hooks, unsigned int valid_hooks) unsigned int *i) { { unsigned int h; unsigned int h; Loading Loading @@ -606,19 +602,14 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, /* Clear counters and comefrom */ /* Clear counters and comefrom */ e->counters = ((struct xt_counters) { 0, 0 }); e->counters = ((struct xt_counters) { 0, 0 }); e->comefrom = 0; e->comefrom = 0; (*i)++; return 0; return 0; } } static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) static inline void cleanup_entry(struct arpt_entry *e) { { struct xt_tgdtor_param par; struct xt_tgdtor_param par; struct arpt_entry_target *t; struct arpt_entry_target *t; if (i && (*i)-- == 0) return 1; t = arpt_get_target(e); t = arpt_get_target(e); par.target = t->u.kernel.target; par.target = t->u.kernel.target; par.targinfo = t->data; par.targinfo = t->data; Loading @@ -626,26 +617,20 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) if (par.target->destroy != NULL) if (par.target->destroy != NULL) par.target->destroy(&par); par.target->destroy(&par); module_put(par.target->me); module_put(par.target->me); return 0; } } /* Checks and translates the user-supplied table segment (held in /* Checks and translates the user-supplied table segment (held in * newinfo). * newinfo). */ */ static int translate_table(const char *name, static int translate_table(struct xt_table_info *newinfo, void *entry0, unsigned int valid_hooks, const struct arpt_replace *repl) struct xt_table_info *newinfo, void *entry0, unsigned int size, unsigned int number, const unsigned int *hook_entries, const unsigned int *underflows) { { struct arpt_entry *iter; unsigned int i; unsigned int i; int ret; int ret = 0; newinfo->size = size; newinfo->size = repl->size; newinfo->number = number; newinfo->number = repl->num_entries; /* Init all hooks to impossible value. */ /* Init all hooks to impossible value. */ for (i = 0; i < NF_ARP_NUMHOOKS; i++) { for (i = 0; i < NF_ARP_NUMHOOKS; i++) { Loading @@ -657,52 +642,61 @@ static int translate_table(const char *name, i = 0; i = 0; /* Walk through entries, checking offsets. */ /* Walk through entries, checking offsets. */ ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, xt_entry_foreach(iter, entry0, newinfo->size) { check_entry_size_and_hooks, ret = check_entry_size_and_hooks(iter, newinfo, entry0, newinfo, entry0 + repl->size, repl->hook_entry, repl->underflow, entry0, repl->valid_hooks); entry0 + size, if (ret != 0) hook_entries, underflows, valid_hooks, &i); break; ++i; } duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); if (ret != 0) if (ret != 0) return ret; return ret; if (i != number) { if (i != repl->num_entries) { duprintf("translate_table: %u not %u entries\n", duprintf("translate_table: %u not %u entries\n", i, number); i, repl->num_entries); return -EINVAL; return -EINVAL; } } /* Check hooks all assigned */ /* Check hooks all assigned */ for (i = 0; i < NF_ARP_NUMHOOKS; i++) { for (i = 0; i < NF_ARP_NUMHOOKS; i++) { /* Only hooks which are valid */ /* Only hooks which are valid */ if (!(valid_hooks & (1 << i))) if (!(repl->valid_hooks & (1 << i))) continue; continue; if (newinfo->hook_entry[i] == 0xFFFFFFFF) { if (newinfo->hook_entry[i] == 0xFFFFFFFF) { duprintf("Invalid hook entry %u %u\n", duprintf("Invalid hook entry %u %u\n", i, hook_entries[i]); i, repl->hook_entry[i]); return -EINVAL; return -EINVAL; } } if (newinfo->underflow[i] == 0xFFFFFFFF) { if (newinfo->underflow[i] == 0xFFFFFFFF) { duprintf("Invalid underflow %u %u\n", duprintf("Invalid underflow %u %u\n", i, underflows[i]); i, repl->underflow[i]); return -EINVAL; return -EINVAL; } } } } if (!mark_source_chains(newinfo, valid_hooks, entry0)) { if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) { duprintf("Looping hook\n"); duprintf("Looping hook\n"); return -ELOOP; return -ELOOP; } } /* Finally, each sanity check must pass */ /* Finally, each sanity check must pass */ i = 0; i = 0; ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size, xt_entry_foreach(iter, entry0, newinfo->size) { find_check_entry, name, size, &i); ret = find_check_entry(iter, repl->name, repl->size); if (ret != 0) break; ++i; } if (ret != 0) { if (ret != 0) { ARPT_ENTRY_ITERATE(entry0, newinfo->size, xt_entry_foreach(iter, entry0, newinfo->size) { cleanup_entry, &i); if (i-- == 0) break; cleanup_entry(iter); } return ret; return ret; } } Loading @@ -715,30 +709,10 @@ static int translate_table(const char *name, return ret; return ret; } } /* Gets counters. */ static inline int add_entry_to_counter(const struct arpt_entry *e, struct xt_counters total[], unsigned int *i) { ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); (*i)++; return 0; } static inline int set_entry_to_counter(const struct arpt_entry *e, struct xt_counters total[], unsigned int *i) { SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); (*i)++; return 0; } static void get_counters(const struct xt_table_info *t, static void get_counters(const struct xt_table_info *t, struct xt_counters counters[]) struct xt_counters counters[]) { { struct arpt_entry *iter; unsigned int cpu; unsigned int cpu; unsigned int i; unsigned int i; unsigned int curcpu; unsigned int curcpu; Loading @@ -754,22 +728,22 @@ static void get_counters(const struct xt_table_info *t, curcpu = smp_processor_id(); curcpu = smp_processor_id(); i = 0; i = 0; ARPT_ENTRY_ITERATE(t->entries[curcpu], xt_entry_foreach(iter, t->entries[curcpu], t->size) { t->size, SET_COUNTER(counters[i], iter->counters.bcnt, set_entry_to_counter, iter->counters.pcnt); counters, ++i; &i); } for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) { if (cpu == curcpu) if (cpu == curcpu) continue; continue; i = 0; i = 0; xt_info_wrlock(cpu); xt_info_wrlock(cpu); ARPT_ENTRY_ITERATE(t->entries[cpu], xt_entry_foreach(iter, t->entries[cpu], t->size) { t->size, ADD_COUNTER(counters[i], iter->counters.bcnt, add_entry_to_counter, iter->counters.pcnt); counters, ++i; &i); } xt_info_wrunlock(cpu); xt_info_wrunlock(cpu); } } local_bh_enable(); local_bh_enable(); Loading Loading @@ -899,7 +873,9 @@ static int compat_calc_entry(const struct arpt_entry *e, static int compat_table_info(const struct xt_table_info *info, static int compat_table_info(const struct xt_table_info *info, struct xt_table_info *newinfo) struct xt_table_info *newinfo) { { struct arpt_entry *iter; void *loc_cpu_entry; void *loc_cpu_entry; int ret; if (!newinfo || !info) if (!newinfo || !info) return -EINVAL; return -EINVAL; Loading @@ -908,9 +884,12 @@ static int compat_table_info(const struct xt_table_info *info, memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); newinfo->initial_entries = 0; newinfo->initial_entries = 0; loc_cpu_entry = info->entries[raw_smp_processor_id()]; loc_cpu_entry = info->entries[raw_smp_processor_id()]; return ARPT_ENTRY_ITERATE(loc_cpu_entry, info->size, xt_entry_foreach(iter, loc_cpu_entry, info->size) { compat_calc_entry, info, loc_cpu_entry, ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); newinfo); if (ret != 0) return ret; } return 0; } } #endif #endif Loading Loading @@ -1025,6 +1004,7 @@ static int __do_replace(struct net *net, const char *name, struct xt_table_info *oldinfo; struct xt_table_info *oldinfo; struct xt_counters *counters; struct xt_counters *counters; void *loc_cpu_old_entry; void *loc_cpu_old_entry; struct arpt_entry *iter; ret = 0; ret = 0; counters = vmalloc_node(num_counters * sizeof(struct xt_counters), counters = vmalloc_node(num_counters * sizeof(struct xt_counters), Loading Loading @@ -1068,8 +1048,8 @@ static int __do_replace(struct net *net, const char *name, /* Decrease module usage counts and free resource */ /* Decrease module usage counts and free resource */ loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) NULL); cleanup_entry(iter); xt_free_table_info(oldinfo); xt_free_table_info(oldinfo); if (copy_to_user(counters_ptr, counters, if (copy_to_user(counters_ptr, counters, Loading @@ -1095,6 +1075,7 @@ static int do_replace(struct net *net, const void __user *user, struct arpt_replace tmp; struct arpt_replace tmp; struct xt_table_info *newinfo; struct xt_table_info *newinfo; void *loc_cpu_entry; void *loc_cpu_entry; struct arpt_entry *iter; if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) return -EFAULT; return -EFAULT; Loading @@ -1115,9 +1096,7 @@ static int do_replace(struct net *net, const void __user *user, goto free_newinfo; goto free_newinfo; } } ret = translate_table(tmp.name, tmp.valid_hooks, ret = translate_table(newinfo, loc_cpu_entry, &tmp); newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, tmp.hook_entry, tmp.underflow); if (ret != 0) if (ret != 0) goto free_newinfo; goto free_newinfo; Loading @@ -1130,25 +1109,13 @@ static int do_replace(struct net *net, const void __user *user, return 0; return 0; free_newinfo_untrans: free_newinfo_untrans: ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) cleanup_entry(iter); free_newinfo: free_newinfo: xt_free_table_info(newinfo); xt_free_table_info(newinfo); return ret; return ret; } } /* We're lazy, and add to the first CPU; overflow works its fey magic * and everything is OK. */ static int add_counter_to_entry(struct arpt_entry *e, const struct xt_counters addme[], unsigned int *i) { ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); (*i)++; return 0; } static int do_add_counters(struct net *net, const void __user *user, static int do_add_counters(struct net *net, const void __user *user, unsigned int len, int compat) unsigned int len, int compat) { { Loading @@ -1163,6 +1130,7 @@ static int do_add_counters(struct net *net, const void __user *user, const struct xt_table_info *private; const struct xt_table_info *private; int ret = 0; int ret = 0; void *loc_cpu_entry; void *loc_cpu_entry; struct arpt_entry *iter; #ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT struct compat_xt_counters_info compat_tmp; struct compat_xt_counters_info compat_tmp; Loading Loading @@ -1220,11 +1188,10 @@ static int do_add_counters(struct net *net, const void __user *user, curcpu = smp_processor_id(); curcpu = smp_processor_id(); loc_cpu_entry = private->entries[curcpu]; loc_cpu_entry = private->entries[curcpu]; xt_info_wrlock(curcpu); xt_info_wrlock(curcpu); ARPT_ENTRY_ITERATE(loc_cpu_entry, xt_entry_foreach(iter, loc_cpu_entry, private->size) { private->size, ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); add_counter_to_entry, ++i; paddc, } &i); xt_info_wrunlock(curcpu); xt_info_wrunlock(curcpu); unlock_up_free: unlock_up_free: local_bh_enable(); local_bh_enable(); Loading @@ -1237,17 +1204,12 @@ static int do_add_counters(struct net *net, const void __user *user, } } #ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT static inline int static inline void compat_release_entry(struct compat_arpt_entry *e) compat_release_entry(struct compat_arpt_entry *e, unsigned int *i) { { struct arpt_entry_target *t; struct arpt_entry_target *t; if (i && (*i)-- == 0) return 1; t = compat_arpt_get_target(e); t = compat_arpt_get_target(e); module_put(t->u.kernel.target->me); module_put(t->u.kernel.target->me); return 0; } } static inline int static inline int Loading @@ -1258,7 +1220,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, const unsigned char *limit, const unsigned char *limit, const unsigned int *hook_entries, const unsigned int *hook_entries, const unsigned int *underflows, const unsigned int *underflows, unsigned int *i, const char *name) const char *name) { { struct arpt_entry_target *t; struct arpt_entry_target *t; Loading Loading @@ -1318,8 +1279,6 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, /* Clear counters and comefrom */ /* Clear counters and comefrom */ memset(&e->counters, 0, sizeof(e->counters)); memset(&e->counters, 0, sizeof(e->counters)); e->comefrom = 0; e->comefrom = 0; (*i)++; return 0; return 0; release_target: release_target: Loading Loading @@ -1363,19 +1322,6 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, return ret; return ret; } } static inline int compat_check_entry(struct arpt_entry *e, const char *name, unsigned int *i) { int ret; ret = check_target(e, name); if (ret) return ret; (*i)++; return 0; } static int translate_compat_table(const char *name, static int translate_compat_table(const char *name, unsigned int valid_hooks, unsigned int valid_hooks, struct xt_table_info **pinfo, struct xt_table_info **pinfo, Loading @@ -1388,8 +1334,10 @@ static int translate_compat_table(const char *name, unsigned int i, j; unsigned int i, j; struct xt_table_info *newinfo, *info; struct xt_table_info *newinfo, *info; void *pos, *entry0, *entry1; void *pos, *entry0, *entry1; struct compat_arpt_entry *iter0; struct arpt_entry *iter1; unsigned int size; unsigned int size; int ret; int ret = 0; info = *pinfo; info = *pinfo; entry0 = *pentry0; entry0 = *pentry0; Loading @@ -1406,13 +1354,14 @@ static int translate_compat_table(const char *name, j = 0; j = 0; xt_compat_lock(NFPROTO_ARP); xt_compat_lock(NFPROTO_ARP); /* Walk through entries, checking offsets. */ /* Walk through entries, checking offsets. */ ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, xt_entry_foreach(iter0, entry0, total_size) { check_compat_entry_size_and_hooks, ret = check_compat_entry_size_and_hooks(iter0, info, &size, info, &size, entry0, entry0, entry0 + total_size, hook_entries, underflows, entry0 + total_size, name); hook_entries, underflows, &j, name); if (ret != 0) if (ret != 0) goto out_unlock; goto out_unlock; ++j; } ret = -EINVAL; ret = -EINVAL; if (j != number) { if (j != number) { Loading Loading @@ -1451,9 +1400,12 @@ static int translate_compat_table(const char *name, entry1 = newinfo->entries[raw_smp_processor_id()]; entry1 = newinfo->entries[raw_smp_processor_id()]; pos = entry1; pos = entry1; size = total_size; size = total_size; ret = COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, xt_entry_foreach(iter0, entry0, total_size) { compat_copy_entry_from_user, ret = compat_copy_entry_from_user(iter0, &pos, &pos, &size, name, newinfo, entry1); &size, name, newinfo, entry1); if (ret != 0) break; } xt_compat_flush_offsets(NFPROTO_ARP); xt_compat_flush_offsets(NFPROTO_ARP); xt_compat_unlock(NFPROTO_ARP); xt_compat_unlock(NFPROTO_ARP); if (ret) if (ret) Loading @@ -1464,13 +1416,32 @@ static int translate_compat_table(const char *name, goto free_newinfo; goto free_newinfo; i = 0; i = 0; ret = ARPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, xt_entry_foreach(iter1, entry1, newinfo->size) { name, &i); ret = check_target(iter1, name); if (ret != 0) break; ++i; } if (ret) { if (ret) { /* * The first i matches need cleanup_entry (calls ->destroy) * because they had called ->check already. The other j-i * entries need only release. */ int skip = i; j -= i; j -= i; COMPAT_ARPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, xt_entry_foreach(iter0, entry0, newinfo->size) { compat_release_entry, &j); if (skip-- > 0) ARPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i); continue; if (j-- == 0) break; compat_release_entry(iter0); } xt_entry_foreach(iter1, entry1, newinfo->size) { if (i-- == 0) break; cleanup_entry(iter1); } xt_free_table_info(newinfo); xt_free_table_info(newinfo); return ret; return ret; } } Loading @@ -1488,7 +1459,11 @@ static int translate_compat_table(const char *name, free_newinfo: free_newinfo: xt_free_table_info(newinfo); xt_free_table_info(newinfo); out: out: COMPAT_ARPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); xt_entry_foreach(iter0, entry0, total_size) { if (j-- == 0) break; compat_release_entry(iter0); } return ret; return ret; out_unlock: out_unlock: xt_compat_flush_offsets(NFPROTO_ARP); xt_compat_flush_offsets(NFPROTO_ARP); Loading @@ -1515,6 +1490,7 @@ static int compat_do_replace(struct net *net, void __user *user, struct compat_arpt_replace tmp; struct compat_arpt_replace tmp; struct xt_table_info *newinfo; struct xt_table_info *newinfo; void *loc_cpu_entry; void *loc_cpu_entry; struct arpt_entry *iter; if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) return -EFAULT; return -EFAULT; Loading Loading @@ -1552,7 +1528,8 @@ static int compat_do_replace(struct net *net, void __user *user, return 0; return 0; free_newinfo_untrans: free_newinfo_untrans: ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) cleanup_entry(iter); free_newinfo: free_newinfo: xt_free_table_info(newinfo); xt_free_table_info(newinfo); return ret; return ret; Loading Loading @@ -1586,7 +1563,7 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, compat_uint_t *size, compat_uint_t *size, struct xt_counters *counters, struct xt_counters *counters, unsigned int *i) unsigned int i) { { struct arpt_entry_target *t; struct arpt_entry_target *t; struct compat_arpt_entry __user *ce; struct compat_arpt_entry __user *ce; Loading @@ -1594,14 +1571,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, compat_uint_t origsize; compat_uint_t origsize; int ret; int ret; ret = -EFAULT; origsize = *size; origsize = *size; ce = (struct compat_arpt_entry __user *)*dstptr; ce = (struct compat_arpt_entry __user *)*dstptr; if (copy_to_user(ce, e, sizeof(struct arpt_entry))) if (copy_to_user(ce, e, sizeof(struct arpt_entry)) != 0 || goto out; copy_to_user(&ce->counters, &counters[i], sizeof(counters[i])) != 0) if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) return -EFAULT; goto out; *dstptr += sizeof(struct compat_arpt_entry); *dstptr += sizeof(struct compat_arpt_entry); *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); *size -= sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry); Loading @@ -1611,18 +1586,12 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr, t = arpt_get_target(e); t = arpt_get_target(e); ret = xt_compat_target_to_user(t, dstptr, size); ret = xt_compat_target_to_user(t, dstptr, size); if (ret) if (ret) goto out; return ret; ret = -EFAULT; next_offset = e->next_offset - (origsize - *size); next_offset = e->next_offset - (origsize - *size); if (put_user(target_offset, &ce->target_offset)) if (put_user(target_offset, &ce->target_offset) != 0 || goto out; put_user(next_offset, &ce->next_offset) != 0) if (put_user(next_offset, &ce->next_offset)) return -EFAULT; goto out; (*i)++; return 0; return 0; out: return ret; } } static int compat_copy_entries_to_user(unsigned int total_size, static int compat_copy_entries_to_user(unsigned int total_size, Loading @@ -1636,6 +1605,7 @@ static int compat_copy_entries_to_user(unsigned int total_size, int ret = 0; int ret = 0; void *loc_cpu_entry; void *loc_cpu_entry; unsigned int i = 0; unsigned int i = 0; struct arpt_entry *iter; counters = alloc_counters(table); counters = alloc_counters(table); if (IS_ERR(counters)) if (IS_ERR(counters)) Loading @@ -1645,9 +1615,12 @@ static int compat_copy_entries_to_user(unsigned int total_size, loc_cpu_entry = private->entries[raw_smp_processor_id()]; loc_cpu_entry = private->entries[raw_smp_processor_id()]; pos = userptr; pos = userptr; size = total_size; size = total_size; ret = ARPT_ENTRY_ITERATE(loc_cpu_entry, total_size, xt_entry_foreach(iter, loc_cpu_entry, total_size) { compat_copy_entry_to_user, ret = compat_copy_entry_to_user(iter, &pos, &pos, &size, counters, &i); &size, counters, i++); if (ret != 0) break; } vfree(counters); vfree(counters); return ret; return ret; } } Loading Loading @@ -1815,12 +1788,7 @@ struct xt_table *arpt_register_table(struct net *net, loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; memcpy(loc_cpu_entry, repl->entries, repl->size); memcpy(loc_cpu_entry, repl->entries, repl->size); ret = translate_table(table->name, table->valid_hooks, ret = translate_table(newinfo, loc_cpu_entry, repl); newinfo, loc_cpu_entry, repl->size, repl->num_entries, repl->hook_entry, repl->underflow); duprintf("arpt_register_table: translate table gives %d\n", ret); duprintf("arpt_register_table: translate table gives %d\n", ret); if (ret != 0) if (ret != 0) goto out_free; goto out_free; Loading @@ -1843,13 +1811,14 @@ void arpt_unregister_table(struct xt_table *table) struct xt_table_info *private; struct xt_table_info *private; void *loc_cpu_entry; void *loc_cpu_entry; struct module *table_owner = table->me; struct module *table_owner = table->me; struct arpt_entry *iter; private = xt_unregister_table(table); private = xt_unregister_table(table); /* Decrease module usage counts and free resources */ /* Decrease module usage counts and free resources */ loc_cpu_entry = private->entries[raw_smp_processor_id()]; loc_cpu_entry = private->entries[raw_smp_processor_id()]; ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size, xt_entry_foreach(iter, loc_cpu_entry, private->size) cleanup_entry, NULL); cleanup_entry(iter); if (private->number > private->initial_entries) if (private->number > private->initial_entries) module_put(table_owner); module_put(table_owner); xt_free_table_info(private); xt_free_table_info(private); Loading