diff options
author | Patrick McHardy <kaber@trash.net> | 2007-12-18 00:47:48 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:58:31 -0500 |
commit | b386d9f5960a9afce7f077edf2095fccfbb1a8e6 (patch) | |
tree | c7ccccf204ef62c239a87943c160a3bf25f97895 | |
parent | 73cd598df46a73d6f02063f2520df115a9b88aa5 (diff) |
[NETFILTER]: ip_tables: move compat offset calculation to x_tables
Its needed by ip6_tables and arp_tables as well.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netfilter/x_tables.h | 4 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 67 | ||||
-rw-r--r-- | net/netfilter/x_tables.c | 58 |
3 files changed, 70 insertions, 59 deletions
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 8ab754e14ec0..b99ede51318a 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h | |||
@@ -424,6 +424,10 @@ struct compat_xt_counters_info | |||
424 | extern void xt_compat_lock(int af); | 424 | extern void xt_compat_lock(int af); |
425 | extern void xt_compat_unlock(int af); | 425 | extern void xt_compat_unlock(int af); |
426 | 426 | ||
427 | extern int xt_compat_add_offset(int af, unsigned int offset, short delta); | ||
428 | extern void xt_compat_flush_offsets(int af); | ||
429 | extern short xt_compat_calc_jump(int af, unsigned int offset); | ||
430 | |||
427 | extern int xt_compat_match_offset(struct xt_match *match); | 431 | extern int xt_compat_match_offset(struct xt_match *match); |
428 | extern int xt_compat_match_from_user(struct xt_entry_match *m, | 432 | extern int xt_compat_match_from_user(struct xt_entry_match *m, |
429 | void **dstptr, int *size); | 433 | void **dstptr, int *size); |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index d8caa1ed4879..07be12cc3fe3 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -1014,63 +1014,12 @@ copy_entries_to_user(unsigned int total_size, | |||
1014 | } | 1014 | } |
1015 | 1015 | ||
1016 | #ifdef CONFIG_COMPAT | 1016 | #ifdef CONFIG_COMPAT |
1017 | struct compat_delta { | ||
1018 | struct compat_delta *next; | ||
1019 | unsigned int offset; | ||
1020 | short delta; | ||
1021 | }; | ||
1022 | |||
1023 | static struct compat_delta *compat_offsets; | ||
1024 | |||
1025 | static int compat_add_offset(unsigned int offset, short delta) | ||
1026 | { | ||
1027 | struct compat_delta *tmp; | ||
1028 | |||
1029 | tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); | ||
1030 | if (!tmp) | ||
1031 | return -ENOMEM; | ||
1032 | tmp->offset = offset; | ||
1033 | tmp->delta = delta; | ||
1034 | if (compat_offsets) { | ||
1035 | tmp->next = compat_offsets->next; | ||
1036 | compat_offsets->next = tmp; | ||
1037 | } else { | ||
1038 | compat_offsets = tmp; | ||
1039 | tmp->next = NULL; | ||
1040 | } | ||
1041 | return 0; | ||
1042 | } | ||
1043 | |||
1044 | static void compat_flush_offsets(void) | ||
1045 | { | ||
1046 | struct compat_delta *tmp, *next; | ||
1047 | |||
1048 | if (compat_offsets) { | ||
1049 | for (tmp = compat_offsets; tmp; tmp = next) { | ||
1050 | next = tmp->next; | ||
1051 | kfree(tmp); | ||
1052 | } | ||
1053 | compat_offsets = NULL; | ||
1054 | } | ||
1055 | } | ||
1056 | |||
1057 | static short compat_calc_jump(unsigned int offset) | ||
1058 | { | ||
1059 | struct compat_delta *tmp; | ||
1060 | short delta; | ||
1061 | |||
1062 | for (tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next) | ||
1063 | if (tmp->offset < offset) | ||
1064 | delta += tmp->delta; | ||
1065 | return delta; | ||
1066 | } | ||
1067 | |||
1068 | static void compat_standard_from_user(void *dst, void *src) | 1017 | static void compat_standard_from_user(void *dst, void *src) |
1069 | { | 1018 | { |
1070 | int v = *(compat_int_t *)src; | 1019 | int v = *(compat_int_t *)src; |
1071 | 1020 | ||
1072 | if (v > 0) | 1021 | if (v > 0) |
1073 | v += compat_calc_jump(v); | 1022 | v += xt_compat_calc_jump(AF_INET, v); |
1074 | memcpy(dst, &v, sizeof(v)); | 1023 | memcpy(dst, &v, sizeof(v)); |
1075 | } | 1024 | } |
1076 | 1025 | ||
@@ -1079,7 +1028,7 @@ static int compat_standard_to_user(void __user *dst, void *src) | |||
1079 | compat_int_t cv = *(int *)src; | 1028 | compat_int_t cv = *(int *)src; |
1080 | 1029 | ||
1081 | if (cv > 0) | 1030 | if (cv > 0) |
1082 | cv -= compat_calc_jump(cv); | 1031 | cv -= xt_compat_calc_jump(AF_INET, cv); |
1083 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; | 1032 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; |
1084 | } | 1033 | } |
1085 | 1034 | ||
@@ -1104,7 +1053,7 @@ static int compat_calc_entry(struct ipt_entry *e, | |||
1104 | t = ipt_get_target(e); | 1053 | t = ipt_get_target(e); |
1105 | off += xt_compat_target_offset(t->u.kernel.target); | 1054 | off += xt_compat_target_offset(t->u.kernel.target); |
1106 | newinfo->size -= off; | 1055 | newinfo->size -= off; |
1107 | ret = compat_add_offset(entry_offset, off); | 1056 | ret = xt_compat_add_offset(AF_INET, entry_offset, off); |
1108 | if (ret) | 1057 | if (ret) |
1109 | return ret; | 1058 | return ret; |
1110 | 1059 | ||
@@ -1167,7 +1116,7 @@ static int get_info(void __user *user, int *len, int compat) | |||
1167 | if (compat) { | 1116 | if (compat) { |
1168 | struct xt_table_info tmp; | 1117 | struct xt_table_info tmp; |
1169 | ret = compat_table_info(private, &tmp); | 1118 | ret = compat_table_info(private, &tmp); |
1170 | compat_flush_offsets(); | 1119 | xt_compat_flush_offsets(AF_INET); |
1171 | private = &tmp; | 1120 | private = &tmp; |
1172 | } | 1121 | } |
1173 | #endif | 1122 | #endif |
@@ -1631,7 +1580,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, | |||
1631 | 1580 | ||
1632 | off += xt_compat_target_offset(target); | 1581 | off += xt_compat_target_offset(target); |
1633 | *size += off; | 1582 | *size += off; |
1634 | ret = compat_add_offset(entry_offset, off); | 1583 | ret = xt_compat_add_offset(AF_INET, entry_offset, off); |
1635 | if (ret) | 1584 | if (ret) |
1636 | goto out; | 1585 | goto out; |
1637 | 1586 | ||
@@ -1797,7 +1746,7 @@ translate_compat_table(const char *name, | |||
1797 | ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, | 1746 | ret = COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, |
1798 | compat_copy_entry_from_user, &pos, &size, | 1747 | compat_copy_entry_from_user, &pos, &size, |
1799 | name, newinfo, entry1); | 1748 | name, newinfo, entry1); |
1800 | compat_flush_offsets(); | 1749 | xt_compat_flush_offsets(AF_INET); |
1801 | xt_compat_unlock(AF_INET); | 1750 | xt_compat_unlock(AF_INET); |
1802 | if (ret) | 1751 | if (ret) |
1803 | goto free_newinfo; | 1752 | goto free_newinfo; |
@@ -1834,7 +1783,7 @@ out: | |||
1834 | COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1783 | COMPAT_IPT_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); |
1835 | return ret; | 1784 | return ret; |
1836 | out_unlock: | 1785 | out_unlock: |
1837 | compat_flush_offsets(); | 1786 | xt_compat_flush_offsets(AF_INET); |
1838 | xt_compat_unlock(AF_INET); | 1787 | xt_compat_unlock(AF_INET); |
1839 | goto out; | 1788 | goto out; |
1840 | } | 1789 | } |
@@ -1997,7 +1946,7 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len) | |||
1997 | get.size); | 1946 | get.size); |
1998 | ret = -EINVAL; | 1947 | ret = -EINVAL; |
1999 | } | 1948 | } |
2000 | compat_flush_offsets(); | 1949 | xt_compat_flush_offsets(AF_INET); |
2001 | module_put(t->me); | 1950 | module_put(t->me); |
2002 | xt_table_unlock(t); | 1951 | xt_table_unlock(t); |
2003 | } else | 1952 | } else |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index b95284ee4fd4..8d4fca96a4a7 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -34,12 +34,21 @@ MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module"); | |||
34 | 34 | ||
35 | #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) | 35 | #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) |
36 | 36 | ||
37 | struct compat_delta { | ||
38 | struct compat_delta *next; | ||
39 | unsigned int offset; | ||
40 | short delta; | ||
41 | }; | ||
42 | |||
37 | struct xt_af { | 43 | struct xt_af { |
38 | struct mutex mutex; | 44 | struct mutex mutex; |
39 | struct list_head match; | 45 | struct list_head match; |
40 | struct list_head target; | 46 | struct list_head target; |
41 | struct list_head tables; | 47 | struct list_head tables; |
48 | #ifdef CONFIG_COMPAT | ||
42 | struct mutex compat_mutex; | 49 | struct mutex compat_mutex; |
50 | struct compat_delta *compat_offsets; | ||
51 | #endif | ||
43 | }; | 52 | }; |
44 | 53 | ||
45 | static struct xt_af *xt; | 54 | static struct xt_af *xt; |
@@ -335,6 +344,54 @@ int xt_check_match(const struct xt_match *match, unsigned short family, | |||
335 | EXPORT_SYMBOL_GPL(xt_check_match); | 344 | EXPORT_SYMBOL_GPL(xt_check_match); |
336 | 345 | ||
337 | #ifdef CONFIG_COMPAT | 346 | #ifdef CONFIG_COMPAT |
347 | int xt_compat_add_offset(int af, unsigned int offset, short delta) | ||
348 | { | ||
349 | struct compat_delta *tmp; | ||
350 | |||
351 | tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); | ||
352 | if (!tmp) | ||
353 | return -ENOMEM; | ||
354 | |||
355 | tmp->offset = offset; | ||
356 | tmp->delta = delta; | ||
357 | |||
358 | if (xt[af].compat_offsets) { | ||
359 | tmp->next = xt[af].compat_offsets->next; | ||
360 | xt[af].compat_offsets->next = tmp; | ||
361 | } else { | ||
362 | xt[af].compat_offsets = tmp; | ||
363 | tmp->next = NULL; | ||
364 | } | ||
365 | return 0; | ||
366 | } | ||
367 | EXPORT_SYMBOL_GPL(xt_compat_add_offset); | ||
368 | |||
369 | void xt_compat_flush_offsets(int af) | ||
370 | { | ||
371 | struct compat_delta *tmp, *next; | ||
372 | |||
373 | if (xt[af].compat_offsets) { | ||
374 | for (tmp = xt[af].compat_offsets; tmp; tmp = next) { | ||
375 | next = tmp->next; | ||
376 | kfree(tmp); | ||
377 | } | ||
378 | xt[af].compat_offsets = NULL; | ||
379 | } | ||
380 | } | ||
381 | EXPORT_SYMBOL_GPL(xt_compat_flush_offsets); | ||
382 | |||
383 | short xt_compat_calc_jump(int af, unsigned int offset) | ||
384 | { | ||
385 | struct compat_delta *tmp; | ||
386 | short delta; | ||
387 | |||
388 | for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next) | ||
389 | if (tmp->offset < offset) | ||
390 | delta += tmp->delta; | ||
391 | return delta; | ||
392 | } | ||
393 | EXPORT_SYMBOL_GPL(xt_compat_calc_jump); | ||
394 | |||
338 | int xt_compat_match_offset(struct xt_match *match) | 395 | int xt_compat_match_offset(struct xt_match *match) |
339 | { | 396 | { |
340 | u_int16_t csize = match->compatsize ? : match->matchsize; | 397 | u_int16_t csize = match->compatsize ? : match->matchsize; |
@@ -873,6 +930,7 @@ static int __init xt_init(void) | |||
873 | mutex_init(&xt[i].mutex); | 930 | mutex_init(&xt[i].mutex); |
874 | #ifdef CONFIG_COMPAT | 931 | #ifdef CONFIG_COMPAT |
875 | mutex_init(&xt[i].compat_mutex); | 932 | mutex_init(&xt[i].compat_mutex); |
933 | xt[i].compat_offsets = NULL; | ||
876 | #endif | 934 | #endif |
877 | INIT_LIST_HEAD(&xt[i].target); | 935 | INIT_LIST_HEAD(&xt[i].target); |
878 | INIT_LIST_HEAD(&xt[i].match); | 936 | INIT_LIST_HEAD(&xt[i].match); |