diff options
author | Patrick McHardy <kaber@trash.net> | 2006-09-20 15:05:37 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 18:20:01 -0400 |
commit | 9fa492cdc160cd27ce1046cb36f47d3b2b1efa21 (patch) | |
tree | 6ecb2a92a87523af2a1f7236f0bca456ca0677f3 /net/ipv4 | |
parent | 79030ed07de673e8451a03aecb9ada9f4d75d491 (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.c | 115 |
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 | ||
945 | struct compat_ipt_standard_target | 945 | static 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 | |||
951 | struct 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 | ||
961 | static int compat_ipt_standard_fn(void *target, | 954 | static 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 | ||
1005 | static inline int | 963 | static inline int |
1006 | compat_calc_match(struct ipt_entry_match *m, int * size) | 964 | compat_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 | ||
1414 | static inline int compat_copy_match_to_user(struct ipt_entry_match *m, | 1366 | static 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 | ||
1424 | static int compat_copy_entry_to_user(struct ipt_entry *e, | 1372 | static 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 | ||