aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/x_tables.h8
-rw-r--r--net/ipv4/netfilter/ip_tables.c33
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
962struct compat_ipt_standard 959struct 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
968static int compat_ipt_standard_fn(void *target, 969static 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;