diff options
-rw-r--r-- | include/linux/netfilter/x_tables.h | 8 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 33 |
2 files changed, 22 insertions, 19 deletions
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 38701454e197..48cc32d83f77 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h | |||
@@ -337,6 +337,10 @@ struct compat_xt_entry_match | |||
337 | char name[XT_FUNCTION_MAXNAMELEN - 1]; | 337 | char name[XT_FUNCTION_MAXNAMELEN - 1]; |
338 | u_int8_t revision; | 338 | u_int8_t revision; |
339 | } user; | 339 | } user; |
340 | struct { | ||
341 | u_int16_t match_size; | ||
342 | compat_uptr_t match; | ||
343 | } kernel; | ||
340 | u_int16_t match_size; | 344 | u_int16_t match_size; |
341 | } u; | 345 | } u; |
342 | unsigned char data[0]; | 346 | unsigned char data[0]; |
@@ -350,6 +354,10 @@ struct compat_xt_entry_target | |||
350 | char name[XT_FUNCTION_MAXNAMELEN - 1]; | 354 | char name[XT_FUNCTION_MAXNAMELEN - 1]; |
351 | u_int8_t revision; | 355 | u_int8_t revision; |
352 | } user; | 356 | } user; |
357 | struct { | ||
358 | u_int16_t target_size; | ||
359 | compat_uptr_t target; | ||
360 | } kernel; | ||
353 | u_int16_t target_size; | 361 | u_int16_t target_size; |
354 | } u; | 362 | } u; |
355 | unsigned char data[0]; | 363 | unsigned char data[0]; |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index d25ac8ba6eba..6d1c11563943 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -956,15 +956,16 @@ struct compat_ipt_standard_target | |||
956 | compat_int_t verdict; | 956 | compat_int_t verdict; |
957 | }; | 957 | }; |
958 | 958 | ||
959 | #define IPT_ST_OFFSET (sizeof(struct ipt_standard_target) - \ | ||
960 | sizeof(struct compat_ipt_standard_target)) | ||
961 | |||
962 | struct compat_ipt_standard | 959 | struct compat_ipt_standard |
963 | { | 960 | { |
964 | struct compat_ipt_entry entry; | 961 | struct compat_ipt_entry entry; |
965 | struct compat_ipt_standard_target target; | 962 | struct compat_ipt_standard_target target; |
966 | }; | 963 | }; |
967 | 964 | ||
965 | #define IPT_ST_LEN XT_ALIGN(sizeof(struct ipt_standard_target)) | ||
966 | #define IPT_ST_COMPAT_LEN COMPAT_XT_ALIGN(sizeof(struct compat_ipt_standard_target)) | ||
967 | #define IPT_ST_OFFSET (IPT_ST_LEN - IPT_ST_COMPAT_LEN) | ||
968 | |||
968 | static int compat_ipt_standard_fn(void *target, | 969 | static int compat_ipt_standard_fn(void *target, |
969 | void **dstptr, int *size, int convert) | 970 | void **dstptr, int *size, int convert) |
970 | { | 971 | { |
@@ -975,35 +976,29 @@ static int compat_ipt_standard_fn(void *target, | |||
975 | ret = 0; | 976 | ret = 0; |
976 | switch (convert) { | 977 | switch (convert) { |
977 | case COMPAT_TO_USER: | 978 | case COMPAT_TO_USER: |
978 | pst = (struct ipt_standard_target *)target; | 979 | pst = target; |
979 | memcpy(&compat_st.target, &pst->target, | 980 | memcpy(&compat_st.target, &pst->target, |
980 | sizeof(struct ipt_entry_target)); | 981 | sizeof(compat_st.target)); |
981 | compat_st.verdict = pst->verdict; | 982 | compat_st.verdict = pst->verdict; |
982 | if (compat_st.verdict > 0) | 983 | if (compat_st.verdict > 0) |
983 | compat_st.verdict -= | 984 | compat_st.verdict -= |
984 | compat_calc_jump(compat_st.verdict); | 985 | compat_calc_jump(compat_st.verdict); |
985 | compat_st.target.u.user.target_size = | 986 | compat_st.target.u.user.target_size = IPT_ST_COMPAT_LEN; |
986 | sizeof(struct compat_ipt_standard_target); | 987 | if (copy_to_user(*dstptr, &compat_st, IPT_ST_COMPAT_LEN)) |
987 | if (__copy_to_user(*dstptr, &compat_st, | ||
988 | sizeof(struct compat_ipt_standard_target))) | ||
989 | ret = -EFAULT; | 988 | ret = -EFAULT; |
990 | *size -= IPT_ST_OFFSET; | 989 | *size -= IPT_ST_OFFSET; |
991 | *dstptr += sizeof(struct compat_ipt_standard_target); | 990 | *dstptr += IPT_ST_COMPAT_LEN; |
992 | break; | 991 | break; |
993 | case COMPAT_FROM_USER: | 992 | case COMPAT_FROM_USER: |
994 | pcompat_st = | 993 | pcompat_st = target; |
995 | (struct compat_ipt_standard_target *)target; | 994 | memcpy(&st.target, &pcompat_st->target, IPT_ST_COMPAT_LEN); |
996 | memcpy(&st.target, &pcompat_st->target, | ||
997 | sizeof(struct ipt_entry_target)); | ||
998 | st.verdict = pcompat_st->verdict; | 995 | st.verdict = pcompat_st->verdict; |
999 | if (st.verdict > 0) | 996 | if (st.verdict > 0) |
1000 | st.verdict += compat_calc_jump(st.verdict); | 997 | st.verdict += compat_calc_jump(st.verdict); |
1001 | st.target.u.user.target_size = | 998 | st.target.u.user.target_size = IPT_ST_LEN; |
1002 | sizeof(struct ipt_standard_target); | 999 | memcpy(*dstptr, &st, IPT_ST_LEN); |
1003 | memcpy(*dstptr, &st, | ||
1004 | sizeof(struct ipt_standard_target)); | ||
1005 | *size += IPT_ST_OFFSET; | 1000 | *size += IPT_ST_OFFSET; |
1006 | *dstptr += sizeof(struct ipt_standard_target); | 1001 | *dstptr += IPT_ST_LEN; |
1007 | break; | 1002 | break; |
1008 | case COMPAT_CALC_SIZE: | 1003 | case COMPAT_CALC_SIZE: |
1009 | *size += IPT_ST_OFFSET; | 1004 | *size += IPT_ST_OFFSET; |