diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 9657c4ee70fc05770050026992ea62e030a4f35e..e305f2d0d4d1d98612d2e91d8e88e4852c6b533b 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -269,9 +269,12 @@ struct xt_table_info unsigned int underflow[NF_INET_NUMHOOKS]; /* ipt_entry tables: one per CPU */ - char *entries[NR_CPUS]; + /* Note : this field MUST be the last one, see XT_TABLE_INFO_SZ */ + char *entries[1]; }; +#define XT_TABLE_INFO_SZ (offsetof(struct xt_table_info, entries) \ + + nr_cpu_ids * sizeof(char *)) extern int xt_register_target(struct xt_target *target); extern void xt_unregister_target(struct xt_target *target); extern int xt_register_targets(struct xt_target *target, unsigned int n); diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 2909c92ecd999b22fc8001d501db48e4882d0eba..a21722d5c9fa44736e99351625a2617f2060c293 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -811,8 +811,7 @@ static int do_replace(void __user *user, unsigned int len) return -ENOPROTOOPT; /* overflow check */ - if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS - - SMP_CACHE_BYTES) + if (tmp.size >= INT_MAX / num_possible_cpus()) return -ENOMEM; if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; @@ -1090,7 +1089,7 @@ int arpt_register_table(struct arpt_table *table, { int ret; struct xt_table_info *newinfo; - static struct xt_table_info bootstrap + struct xt_table_info bootstrap = { 0, 0, 0, { 0 }, { 0 }, { } }; void *loc_cpu_entry; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index ca23c63ced37841338745f6a37b66fb6d191dd09..87d369244bd9433c431e38c782a5b2690d5efa92 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1090,7 +1090,8 @@ compat_calc_match(struct ipt_entry_match *m, int * size) return 0; } -static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info, +static int compat_calc_entry(struct ipt_entry *e, + const struct xt_table_info *info, void *base, struct xt_table_info *newinfo) { struct ipt_entry_target *t; @@ -1118,22 +1119,17 @@ static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info, return 0; } -static int compat_table_info(struct xt_table_info *info, +static int compat_table_info(const struct xt_table_info *info, struct xt_table_info *newinfo) { void *loc_cpu_entry; - int i; if (!newinfo || !info) return -EINVAL; - memset(newinfo, 0, sizeof(struct xt_table_info)); - newinfo->size = info->size; - newinfo->number = info->number; - for (i = 0; i < NF_INET_NUMHOOKS; i++) { - newinfo->hook_entry[i] = info->hook_entry[i]; - newinfo->underflow[i] = info->underflow[i]; - } + /* we dont care about newinfo->entries[] */ + memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); + newinfo->initial_entries = 0; loc_cpu_entry = info->entries[raw_smp_processor_id()]; return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size, compat_calc_entry, info, loc_cpu_entry, newinfo); @@ -1327,8 +1323,7 @@ do_replace(void __user *user, unsigned int len) return -ENOPROTOOPT; /* overflow check */ - if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS - - SMP_CACHE_BYTES) + if (tmp.size >= INT_MAX / num_possible_cpus()) return -ENOMEM; if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; @@ -1868,8 +1863,7 @@ compat_do_replace(void __user *user, unsigned int len) return -ENOPROTOOPT; /* overflow check */ - if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS - - SMP_CACHE_BYTES) + if (tmp.size >= INT_MAX / num_possible_cpus()) return -ENOMEM; if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; @@ -2126,7 +2120,7 @@ int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl) { int ret; struct xt_table_info *newinfo; - static struct xt_table_info bootstrap + struct xt_table_info bootstrap = { 0, 0, 0, { 0 }, { 0 }, { } }; void *loc_cpu_entry; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index e1e87eff4686fac625b4e1dd089f9bee94de720c..e60c1b4b1ec8c6112d46583243d92abef1e54eb4 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1042,8 +1042,7 @@ do_replace(void __user *user, unsigned int len) return -EFAULT; /* overflow check */ - if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS - - SMP_CACHE_BYTES) + if (tmp.size >= INT_MAX / num_possible_cpus()) return -ENOMEM; if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)) return -ENOMEM; @@ -1339,7 +1338,7 @@ int ip6t_register_table(struct xt_table *table, { int ret; struct xt_table_info *newinfo; - static struct xt_table_info bootstrap + struct xt_table_info bootstrap = { 0, 0, 0, { 0 }, { 0 }, { } }; void *loc_cpu_entry; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index b6160e41eb1ca978e070631b0fc631dbe6d409d5..07bb465d951814f623fc2d4be21cc448d208d5ab 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -499,7 +499,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size) if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages) return NULL; - newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL); + newinfo = kzalloc(XT_TABLE_INFO_SZ, GFP_KERNEL); if (!newinfo) return NULL;