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 673581db986..800067d69a9 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 | ||
