aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-09-20 15:05:37 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 18:20:01 -0400
commit9fa492cdc160cd27ce1046cb36f47d3b2b1efa21 (patch)
tree6ecb2a92a87523af2a1f7236f0bca456ca0677f3 /net/ipv4
parent79030ed07de673e8451a03aecb9ada9f4d75d491 (diff)
[NETFILTER]: x_tables: simplify compat API
Split the xt_compat_match/xt_compat_target into smaller type-safe functions performing just one operation. Handle all alignment and size-related conversions centrally in these function instead of requiring each module to implement a full-blown conversion function. Replace ->compat callback by ->compat_from_user and ->compat_to_user callbacks, responsible for converting just a single private structure. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/ip_tables.c115
1 files changed, 24 insertions, 91 deletions
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 673581db986e..800067d69a9a 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -942,73 +942,28 @@ static short compat_calc_jump(u_int16_t offset)
942 return delta; 942 return delta;
943} 943}
944 944
945struct compat_ipt_standard_target 945static void compat_standard_from_user(void *dst, void *src)
946{ 946{
947 struct compat_xt_entry_target target; 947 int v = *(compat_int_t *)src;
948 compat_int_t verdict;
949};
950
951struct compat_ipt_standard
952{
953 struct compat_ipt_entry entry;
954 struct compat_ipt_standard_target target;
955};
956 948
957#define IPT_ST_LEN XT_ALIGN(sizeof(struct ipt_standard_target)) 949 if (v > 0)
958#define IPT_ST_COMPAT_LEN COMPAT_XT_ALIGN(sizeof(struct compat_ipt_standard_target)) 950 v += compat_calc_jump(v);
959#define IPT_ST_OFFSET (IPT_ST_LEN - IPT_ST_COMPAT_LEN) 951 memcpy(dst, &v, sizeof(v));
952}
960 953
961static int compat_ipt_standard_fn(void *target, 954static int compat_standard_to_user(void __user *dst, void *src)
962 void **dstptr, int *size, int convert)
963{ 955{
964 struct compat_ipt_standard_target compat_st, *pcompat_st; 956 compat_int_t cv = *(int *)src;
965 struct ipt_standard_target st, *pst;
966 int ret;
967 957
968 ret = 0; 958 if (cv > 0)
969 switch (convert) { 959 cv -= compat_calc_jump(cv);
970 case COMPAT_TO_USER: 960 return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
971 pst = target;
972 memcpy(&compat_st.target, &pst->target,
973 sizeof(compat_st.target));
974 compat_st.verdict = pst->verdict;
975 if (compat_st.verdict > 0)
976 compat_st.verdict -=
977 compat_calc_jump(compat_st.verdict);
978 compat_st.target.u.user.target_size = IPT_ST_COMPAT_LEN;
979 if (copy_to_user(*dstptr, &compat_st, IPT_ST_COMPAT_LEN))
980 ret = -EFAULT;
981 *size -= IPT_ST_OFFSET;
982 *dstptr += IPT_ST_COMPAT_LEN;
983 break;
984 case COMPAT_FROM_USER:
985 pcompat_st = target;
986 memcpy(&st.target, &pcompat_st->target, IPT_ST_COMPAT_LEN);
987 st.verdict = pcompat_st->verdict;
988 if (st.verdict > 0)
989 st.verdict += compat_calc_jump(st.verdict);
990 st.target.u.user.target_size = IPT_ST_LEN;
991 memcpy(*dstptr, &st, IPT_ST_LEN);
992 *size += IPT_ST_OFFSET;
993 *dstptr += IPT_ST_LEN;
994 break;
995 case COMPAT_CALC_SIZE:
996 *size += IPT_ST_OFFSET;
997 break;
998 default:
999 ret = -ENOPROTOOPT;
1000 break;
1001 }
1002 return ret;
1003} 961}
1004 962
1005static inline int 963static inline int
1006compat_calc_match(struct ipt_entry_match *m, int * size) 964compat_calc_match(struct ipt_entry_match *m, int * size)
1007{ 965{
1008 if (m->u.kernel.match->compat) 966 *size += xt_compat_match_offset(m->u.kernel.match);
1009 m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
1010 else
1011 xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
1012 return 0; 967 return 0;
1013} 968}
1014 969
@@ -1023,10 +978,7 @@ static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
1023 entry_offset = (void *)e - base; 978 entry_offset = (void *)e - base;
1024 IPT_MATCH_ITERATE(e, compat_calc_match, &off); 979 IPT_MATCH_ITERATE(e, compat_calc_match, &off);
1025 t = ipt_get_target(e); 980 t = ipt_get_target(e);
1026 if (t->u.kernel.target->compat) 981 off += xt_compat_target_offset(t->u.kernel.target);
1027 t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
1028 else
1029 xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
1030 newinfo->size -= off; 982 newinfo->size -= off;
1031 ret = compat_add_offset(entry_offset, off); 983 ret = compat_add_offset(entry_offset, off);
1032 if (ret) 984 if (ret)
@@ -1412,17 +1364,13 @@ struct compat_ipt_replace {
1412}; 1364};
1413 1365
1414static inline int compat_copy_match_to_user(struct ipt_entry_match *m, 1366static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
1415 void __user **dstptr, compat_uint_t *size) 1367 void * __user *dstptr, compat_uint_t *size)
1416{ 1368{
1417 if (m->u.kernel.match->compat) 1369 return xt_compat_match_to_user(m, dstptr, size);
1418 return m->u.kernel.match->compat(m, dstptr, size,
1419 COMPAT_TO_USER);
1420 else
1421 return xt_compat_match(m, dstptr, size, COMPAT_TO_USER);
1422} 1370}
1423 1371
1424static int compat_copy_entry_to_user(struct ipt_entry *e, 1372static int compat_copy_entry_to_user(struct ipt_entry *e,
1425 void __user **dstptr, compat_uint_t *size) 1373 void * __user *dstptr, compat_uint_t *size)
1426{ 1374{
1427 struct ipt_entry_target __user *t; 1375 struct ipt_entry_target __user *t;
1428 struct compat_ipt_entry __user *ce; 1376 struct compat_ipt_entry __user *ce;
@@ -1442,11 +1390,7 @@ static int compat_copy_entry_to_user(struct ipt_entry *e,
1442 if (ret) 1390 if (ret)
1443 goto out; 1391 goto out;
1444 t = ipt_get_target(e); 1392 t = ipt_get_target(e);
1445 if (t->u.kernel.target->compat) 1393 ret = xt_compat_target_to_user(t, dstptr, size);
1446 ret = t->u.kernel.target->compat(t, dstptr, size,
1447 COMPAT_TO_USER);
1448 else
1449 ret = xt_compat_target(t, dstptr, size, COMPAT_TO_USER);
1450 if (ret) 1394 if (ret)
1451 goto out; 1395 goto out;
1452 ret = -EFAULT; 1396 ret = -EFAULT;
@@ -1478,11 +1422,7 @@ compat_check_calc_match(struct ipt_entry_match *m,
1478 return match ? PTR_ERR(match) : -ENOENT; 1422 return match ? PTR_ERR(match) : -ENOENT;
1479 } 1423 }
1480 m->u.kernel.match = match; 1424 m->u.kernel.match = match;
1481 1425 *size += xt_compat_match_offset(match);
1482 if (m->u.kernel.match->compat)
1483 m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
1484 else
1485 xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
1486 1426
1487 (*i)++; 1427 (*i)++;
1488 return 0; 1428 return 0;
@@ -1543,10 +1483,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e,
1543 } 1483 }
1544 t->u.kernel.target = target; 1484 t->u.kernel.target = target;
1545 1485
1546 if (t->u.kernel.target->compat) 1486 off += xt_compat_target_offset(target);
1547 t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
1548 else
1549 xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
1550 *size += off; 1487 *size += off;
1551 ret = compat_add_offset(entry_offset, off); 1488 ret = compat_add_offset(entry_offset, off);
1552 if (ret) 1489 if (ret)
@@ -1584,10 +1521,7 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
1584 1521
1585 dm = (struct ipt_entry_match *)*dstptr; 1522 dm = (struct ipt_entry_match *)*dstptr;
1586 match = m->u.kernel.match; 1523 match = m->u.kernel.match;
1587 if (match->compat) 1524 xt_compat_match_from_user(m, dstptr, size);
1588 match->compat(m, dstptr, size, COMPAT_FROM_USER);
1589 else
1590 xt_compat_match(m, dstptr, size, COMPAT_FROM_USER);
1591 1525
1592 ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), 1526 ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
1593 name, hookmask, ip->proto, 1527 name, hookmask, ip->proto,
@@ -1635,10 +1569,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
1635 de->target_offset = e->target_offset - (origsize - *size); 1569 de->target_offset = e->target_offset - (origsize - *size);
1636 t = ipt_get_target(e); 1570 t = ipt_get_target(e);
1637 target = t->u.kernel.target; 1571 target = t->u.kernel.target;
1638 if (target->compat) 1572 xt_compat_target_from_user(t, dstptr, size);
1639 target->compat(t, dstptr, size, COMPAT_FROM_USER);
1640 else
1641 xt_compat_target(t, dstptr, size, COMPAT_FROM_USER);
1642 1573
1643 de->next_offset = e->next_offset - (origsize - *size); 1574 de->next_offset = e->next_offset - (origsize - *size);
1644 for (h = 0; h < NF_IP_NUMHOOKS; h++) { 1575 for (h = 0; h < NF_IP_NUMHOOKS; h++) {
@@ -2205,7 +2136,9 @@ static struct ipt_target ipt_standard_target = {
2205 .targetsize = sizeof(int), 2136 .targetsize = sizeof(int),
2206 .family = AF_INET, 2137 .family = AF_INET,
2207#ifdef CONFIG_COMPAT 2138#ifdef CONFIG_COMPAT
2208 .compat = &compat_ipt_standard_fn, 2139 .compatsize = sizeof(compat_int_t),
2140 .compat_from_user = compat_standard_from_user,
2141 .compat_to_user = compat_standard_to_user,
2209#endif 2142#endif
2210}; 2143};
2211 2144