Loading include/linux/netfilter/x_tables.h +4 −0 Original line number Diff line number Diff line Loading @@ -424,6 +424,10 @@ struct compat_xt_counters_info extern void xt_compat_lock(int af); extern void xt_compat_unlock(int af); extern int xt_compat_add_offset(int af, unsigned int offset, short delta); extern void xt_compat_flush_offsets(int af); extern short xt_compat_calc_jump(int af, unsigned int offset); extern int xt_compat_match_offset(struct xt_match *match); extern int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, int *size); Loading net/ipv4/netfilter/ip_tables.c +8 −59 Original line number Diff line number Diff line Loading @@ -1014,63 +1014,12 @@ copy_entries_to_user(unsigned int total_size, } #ifdef CONFIG_COMPAT struct compat_delta { struct compat_delta *next; unsigned int offset; short delta; }; static struct compat_delta *compat_offsets; static int compat_add_offset(unsigned int offset, short delta) { struct compat_delta *tmp; tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); if (!tmp) return -ENOMEM; tmp->offset = offset; tmp->delta = delta; if (compat_offsets) { tmp->next = compat_offsets->next; compat_offsets->next = tmp; } else { compat_offsets = tmp; tmp->next = NULL; } return 0; } static void compat_flush_offsets(void) { struct compat_delta *tmp, *next; if (compat_offsets) { for (tmp = compat_offsets; tmp; tmp = next) { next = tmp->next; kfree(tmp); } compat_offsets = NULL; } } static short compat_calc_jump(unsigned int offset) { struct compat_delta *tmp; short delta; for (tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next) if (tmp->offset < offset) delta += tmp->delta; return delta; } static void compat_standard_from_user(void *dst, void *src) { int v = *(compat_int_t *)src; if (v > 0) v += compat_calc_jump(v); v += xt_compat_calc_jump(AF_INET, v); memcpy(dst, &v, sizeof(v)); } Loading @@ -1079,7 +1028,7 @@ static int compat_standard_to_user(void __user *dst, void *src) compat_int_t cv = *(int *)src; if (cv > 0) cv -= compat_calc_jump(cv); cv -= xt_compat_calc_jump(AF_INET, cv); return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; } Loading @@ -1104,7 +1053,7 @@ static int compat_calc_entry(struct ipt_entry *e, t = ipt_get_target(e); off += xt_compat_target_offset(t->u.kernel.target); newinfo->size -= off; ret = compat_add_offset(entry_offset, off); ret = xt_compat_add_offset(AF_INET, entry_offset, off); if (ret) return ret; Loading Loading @@ -1167,7 +1116,7 @@ static int get_info(void __user *user, int *len, int compat) if (compat) { struct xt_table_info tmp; ret = compat_table_info(private, &tmp); compat_flush_offsets(); xt_compat_flush_offsets(AF_INET); private = &tmp; } #endif Loading Loading @@ -1631,7 +1580,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, off += xt_compat_target_offset(target); *size += off; ret = compat_add_offset(entry_offset, off); ret = xt_compat_add_offset(AF_INET, entry_offset, off); if (ret) goto out; Loading Loading @@ -1797,7 +1746,7 @@ translate_compat_table(const char *name, ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_copy_entry_from_user, &pos, &size, name, newinfo, entry1); compat_flush_offsets(); xt_compat_flush_offsets(AF_INET); xt_compat_unlock(AF_INET); if (ret) goto free_newinfo; Loading Loading @@ -1834,7 +1783,7 @@ translate_compat_table(const char *name, COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); return ret; out_unlock: compat_flush_offsets(); xt_compat_flush_offsets(AF_INET); xt_compat_unlock(AF_INET); goto out; } Loading Loading @@ -1997,7 +1946,7 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len) get.size); ret = -EINVAL; } compat_flush_offsets(); xt_compat_flush_offsets(AF_INET); module_put(t->me); xt_table_unlock(t); } else Loading net/netfilter/x_tables.c +58 −0 Original line number Diff line number Diff line Loading @@ -34,12 +34,21 @@ MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module"); #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) struct compat_delta { struct compat_delta *next; unsigned int offset; short delta; }; struct xt_af { struct mutex mutex; struct list_head match; struct list_head target; struct list_head tables; #ifdef CONFIG_COMPAT struct mutex compat_mutex; struct compat_delta *compat_offsets; #endif }; static struct xt_af *xt; Loading Loading @@ -335,6 +344,54 @@ int xt_check_match(const struct xt_match *match, unsigned short family, EXPORT_SYMBOL_GPL(xt_check_match); #ifdef CONFIG_COMPAT int xt_compat_add_offset(int af, unsigned int offset, short delta) { struct compat_delta *tmp; tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); if (!tmp) return -ENOMEM; tmp->offset = offset; tmp->delta = delta; if (xt[af].compat_offsets) { tmp->next = xt[af].compat_offsets->next; xt[af].compat_offsets->next = tmp; } else { xt[af].compat_offsets = tmp; tmp->next = NULL; } return 0; } EXPORT_SYMBOL_GPL(xt_compat_add_offset); void xt_compat_flush_offsets(int af) { struct compat_delta *tmp, *next; if (xt[af].compat_offsets) { for (tmp = xt[af].compat_offsets; tmp; tmp = next) { next = tmp->next; kfree(tmp); } xt[af].compat_offsets = NULL; } } EXPORT_SYMBOL_GPL(xt_compat_flush_offsets); short xt_compat_calc_jump(int af, unsigned int offset) { struct compat_delta *tmp; short delta; for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next) if (tmp->offset < offset) delta += tmp->delta; return delta; } EXPORT_SYMBOL_GPL(xt_compat_calc_jump); int xt_compat_match_offset(struct xt_match *match) { u_int16_t csize = match->compatsize ? : match->matchsize; Loading Loading @@ -873,6 +930,7 @@ static int __init xt_init(void) mutex_init(&xt[i].mutex); #ifdef CONFIG_COMPAT mutex_init(&xt[i].compat_mutex); xt[i].compat_offsets = NULL; #endif INIT_LIST_HEAD(&xt[i].target); INIT_LIST_HEAD(&xt[i].match); Loading Loading
include/linux/netfilter/x_tables.h +4 −0 Original line number Diff line number Diff line Loading @@ -424,6 +424,10 @@ struct compat_xt_counters_info extern void xt_compat_lock(int af); extern void xt_compat_unlock(int af); extern int xt_compat_add_offset(int af, unsigned int offset, short delta); extern void xt_compat_flush_offsets(int af); extern short xt_compat_calc_jump(int af, unsigned int offset); extern int xt_compat_match_offset(struct xt_match *match); extern int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, int *size); Loading
net/ipv4/netfilter/ip_tables.c +8 −59 Original line number Diff line number Diff line Loading @@ -1014,63 +1014,12 @@ copy_entries_to_user(unsigned int total_size, } #ifdef CONFIG_COMPAT struct compat_delta { struct compat_delta *next; unsigned int offset; short delta; }; static struct compat_delta *compat_offsets; static int compat_add_offset(unsigned int offset, short delta) { struct compat_delta *tmp; tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); if (!tmp) return -ENOMEM; tmp->offset = offset; tmp->delta = delta; if (compat_offsets) { tmp->next = compat_offsets->next; compat_offsets->next = tmp; } else { compat_offsets = tmp; tmp->next = NULL; } return 0; } static void compat_flush_offsets(void) { struct compat_delta *tmp, *next; if (compat_offsets) { for (tmp = compat_offsets; tmp; tmp = next) { next = tmp->next; kfree(tmp); } compat_offsets = NULL; } } static short compat_calc_jump(unsigned int offset) { struct compat_delta *tmp; short delta; for (tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next) if (tmp->offset < offset) delta += tmp->delta; return delta; } static void compat_standard_from_user(void *dst, void *src) { int v = *(compat_int_t *)src; if (v > 0) v += compat_calc_jump(v); v += xt_compat_calc_jump(AF_INET, v); memcpy(dst, &v, sizeof(v)); } Loading @@ -1079,7 +1028,7 @@ static int compat_standard_to_user(void __user *dst, void *src) compat_int_t cv = *(int *)src; if (cv > 0) cv -= compat_calc_jump(cv); cv -= xt_compat_calc_jump(AF_INET, cv); return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; } Loading @@ -1104,7 +1053,7 @@ static int compat_calc_entry(struct ipt_entry *e, t = ipt_get_target(e); off += xt_compat_target_offset(t->u.kernel.target); newinfo->size -= off; ret = compat_add_offset(entry_offset, off); ret = xt_compat_add_offset(AF_INET, entry_offset, off); if (ret) return ret; Loading Loading @@ -1167,7 +1116,7 @@ static int get_info(void __user *user, int *len, int compat) if (compat) { struct xt_table_info tmp; ret = compat_table_info(private, &tmp); compat_flush_offsets(); xt_compat_flush_offsets(AF_INET); private = &tmp; } #endif Loading Loading @@ -1631,7 +1580,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, off += xt_compat_target_offset(target); *size += off; ret = compat_add_offset(entry_offset, off); ret = xt_compat_add_offset(AF_INET, entry_offset, off); if (ret) goto out; Loading Loading @@ -1797,7 +1746,7 @@ translate_compat_table(const char *name, ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_copy_entry_from_user, &pos, &size, name, newinfo, entry1); compat_flush_offsets(); xt_compat_flush_offsets(AF_INET); xt_compat_unlock(AF_INET); if (ret) goto free_newinfo; Loading Loading @@ -1834,7 +1783,7 @@ translate_compat_table(const char *name, COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); return ret; out_unlock: compat_flush_offsets(); xt_compat_flush_offsets(AF_INET); xt_compat_unlock(AF_INET); goto out; } Loading Loading @@ -1997,7 +1946,7 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len) get.size); ret = -EINVAL; } compat_flush_offsets(); xt_compat_flush_offsets(AF_INET); module_put(t->me); xt_table_unlock(t); } else Loading
net/netfilter/x_tables.c +58 −0 Original line number Diff line number Diff line Loading @@ -34,12 +34,21 @@ MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module"); #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) struct compat_delta { struct compat_delta *next; unsigned int offset; short delta; }; struct xt_af { struct mutex mutex; struct list_head match; struct list_head target; struct list_head tables; #ifdef CONFIG_COMPAT struct mutex compat_mutex; struct compat_delta *compat_offsets; #endif }; static struct xt_af *xt; Loading Loading @@ -335,6 +344,54 @@ int xt_check_match(const struct xt_match *match, unsigned short family, EXPORT_SYMBOL_GPL(xt_check_match); #ifdef CONFIG_COMPAT int xt_compat_add_offset(int af, unsigned int offset, short delta) { struct compat_delta *tmp; tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); if (!tmp) return -ENOMEM; tmp->offset = offset; tmp->delta = delta; if (xt[af].compat_offsets) { tmp->next = xt[af].compat_offsets->next; xt[af].compat_offsets->next = tmp; } else { xt[af].compat_offsets = tmp; tmp->next = NULL; } return 0; } EXPORT_SYMBOL_GPL(xt_compat_add_offset); void xt_compat_flush_offsets(int af) { struct compat_delta *tmp, *next; if (xt[af].compat_offsets) { for (tmp = xt[af].compat_offsets; tmp; tmp = next) { next = tmp->next; kfree(tmp); } xt[af].compat_offsets = NULL; } } EXPORT_SYMBOL_GPL(xt_compat_flush_offsets); short xt_compat_calc_jump(int af, unsigned int offset) { struct compat_delta *tmp; short delta; for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next) if (tmp->offset < offset) delta += tmp->delta; return delta; } EXPORT_SYMBOL_GPL(xt_compat_calc_jump); int xt_compat_match_offset(struct xt_match *match) { u_int16_t csize = match->compatsize ? : match->matchsize; Loading Loading @@ -873,6 +930,7 @@ static int __init xt_init(void) mutex_init(&xt[i].mutex); #ifdef CONFIG_COMPAT mutex_init(&xt[i].compat_mutex); xt[i].compat_offsets = NULL; #endif INIT_LIST_HEAD(&xt[i].target); INIT_LIST_HEAD(&xt[i].match); Loading