aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-rw-r--r--net/ipv4/netfilter/ip_tables.c115
-rw-r--r--net/netfilter/x_tables.c192
2 files changed, 133 insertions, 174 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
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index be7baf4f6846..58522fc65d33 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -333,52 +333,65 @@ int xt_check_match(const struct xt_match *match, unsigned short family,
333EXPORT_SYMBOL_GPL(xt_check_match); 333EXPORT_SYMBOL_GPL(xt_check_match);
334 334
335#ifdef CONFIG_COMPAT 335#ifdef CONFIG_COMPAT
336int xt_compat_match(void *match, void **dstptr, int *size, int convert) 336int xt_compat_match_offset(struct xt_match *match)
337{ 337{
338 struct xt_match *m; 338 u_int16_t csize = match->compatsize ? : match->matchsize;
339 struct compat_xt_entry_match *pcompat_m; 339 return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
340 struct xt_entry_match *pm; 340}
341 u_int16_t msize; 341EXPORT_SYMBOL_GPL(xt_compat_match_offset);
342 int off, ret;
343 342
344 ret = 0; 343void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
345 m = ((struct xt_entry_match *)match)->u.kernel.match; 344 int *size)
346 off = XT_ALIGN(m->matchsize) - COMPAT_XT_ALIGN(m->matchsize); 345{
347 switch (convert) { 346 struct xt_match *match = m->u.kernel.match;
348 case COMPAT_TO_USER: 347 struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
349 pm = (struct xt_entry_match *)match; 348 int pad, off = xt_compat_match_offset(match);
350 msize = pm->u.user.match_size; 349 u_int16_t msize = cm->u.user.match_size;
351 if (copy_to_user(*dstptr, pm, msize)) { 350
352 ret = -EFAULT; 351 m = *dstptr;
353 break; 352 memcpy(m, cm, sizeof(*cm));
354 } 353 if (match->compat_from_user)
355 msize -= off; 354 match->compat_from_user(m->data, cm->data);
356 if (put_user(msize, (u_int16_t *)*dstptr)) 355 else
357 ret = -EFAULT; 356 memcpy(m->data, cm->data, msize - sizeof(*cm));
358 *size -= off; 357 pad = XT_ALIGN(match->matchsize) - match->matchsize;
359 *dstptr += msize; 358 if (pad > 0)
360 break; 359 memset(m->data + match->matchsize, 0, pad);
361 case COMPAT_FROM_USER: 360
362 pcompat_m = (struct compat_xt_entry_match *)match; 361 msize += off;
363 pm = (struct xt_entry_match *)*dstptr; 362 m->u.user.match_size = msize;
364 msize = pcompat_m->u.user.match_size; 363
365 memcpy(pm, pcompat_m, msize); 364 *size += off;
366 msize += off; 365 *dstptr += msize;
367 pm->u.user.match_size = msize; 366}
368 *size += off; 367EXPORT_SYMBOL_GPL(xt_compat_match_from_user);
369 *dstptr += msize; 368
370 break; 369int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr,
371 case COMPAT_CALC_SIZE: 370 int *size)
372 *size += off; 371{
373 break; 372 struct xt_match *match = m->u.kernel.match;
374 default: 373 struct compat_xt_entry_match __user *cm = *dstptr;
375 ret = -ENOPROTOOPT; 374 int off = xt_compat_match_offset(match);
376 break; 375 u_int16_t msize = m->u.user.match_size - off;
376
377 if (copy_to_user(cm, m, sizeof(*cm)) ||
378 put_user(msize, &cm->u.user.match_size))
379 return -EFAULT;
380
381 if (match->compat_to_user) {
382 if (match->compat_to_user((void __user *)cm->data, m->data))
383 return -EFAULT;
384 } else {
385 if (copy_to_user(cm->data, m->data, msize - sizeof(*cm)))
386 return -EFAULT;
377 } 387 }
378 return ret; 388
389 *size -= off;
390 *dstptr += msize;
391 return 0;
379} 392}
380EXPORT_SYMBOL_GPL(xt_compat_match); 393EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
381#endif 394#endif /* CONFIG_COMPAT */
382 395
383int xt_check_target(const struct xt_target *target, unsigned short family, 396int xt_check_target(const struct xt_target *target, unsigned short family,
384 unsigned int size, const char *table, unsigned int hook_mask, 397 unsigned int size, const char *table, unsigned int hook_mask,
@@ -410,51 +423,64 @@ int xt_check_target(const struct xt_target *target, unsigned short family,
410EXPORT_SYMBOL_GPL(xt_check_target); 423EXPORT_SYMBOL_GPL(xt_check_target);
411 424
412#ifdef CONFIG_COMPAT 425#ifdef CONFIG_COMPAT
413int xt_compat_target(void *target, void **dstptr, int *size, int convert) 426int xt_compat_target_offset(struct xt_target *target)
414{ 427{
415 struct xt_target *t; 428 u_int16_t csize = target->compatsize ? : target->targetsize;
416 struct compat_xt_entry_target *pcompat; 429 return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
417 struct xt_entry_target *pt; 430}
418 u_int16_t tsize; 431EXPORT_SYMBOL_GPL(xt_compat_target_offset);
419 int off, ret;
420 432
421 ret = 0; 433void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
422 t = ((struct xt_entry_target *)target)->u.kernel.target; 434 int *size)
423 off = XT_ALIGN(t->targetsize) - COMPAT_XT_ALIGN(t->targetsize); 435{
424 switch (convert) { 436 struct xt_target *target = t->u.kernel.target;
425 case COMPAT_TO_USER: 437 struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
426 pt = (struct xt_entry_target *)target; 438 int pad, off = xt_compat_target_offset(target);
427 tsize = pt->u.user.target_size; 439 u_int16_t tsize = ct->u.user.target_size;
428 if (copy_to_user(*dstptr, pt, tsize)) { 440
429 ret = -EFAULT; 441 t = *dstptr;
430 break; 442 memcpy(t, ct, sizeof(*ct));
431 } 443 if (target->compat_from_user)
432 tsize -= off; 444 target->compat_from_user(t->data, ct->data);
433 if (put_user(tsize, (u_int16_t *)*dstptr)) 445 else
434 ret = -EFAULT; 446 memcpy(t->data, ct->data, tsize - sizeof(*ct));
435 *size -= off; 447 pad = XT_ALIGN(target->targetsize) - target->targetsize;
436 *dstptr += tsize; 448 if (pad > 0)
437 break; 449 memset(t->data + target->targetsize, 0, pad);
438 case COMPAT_FROM_USER: 450
439 pcompat = (struct compat_xt_entry_target *)target; 451 tsize += off;
440 pt = (struct xt_entry_target *)*dstptr; 452 t->u.user.target_size = tsize;
441 tsize = pcompat->u.user.target_size; 453
442 memcpy(pt, pcompat, tsize); 454 *size += off;
443 tsize += off; 455 *dstptr += tsize;
444 pt->u.user.target_size = tsize; 456}
445 *size += off; 457EXPORT_SYMBOL_GPL(xt_compat_target_from_user);
446 *dstptr += tsize; 458
447 break; 459int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr,
448 case COMPAT_CALC_SIZE: 460 int *size)
449 *size += off; 461{
450 break; 462 struct xt_target *target = t->u.kernel.target;
451 default: 463 struct compat_xt_entry_target __user *ct = *dstptr;
452 ret = -ENOPROTOOPT; 464 int off = xt_compat_target_offset(target);
453 break; 465 u_int16_t tsize = t->u.user.target_size - off;
466
467 if (copy_to_user(ct, t, sizeof(*ct)) ||
468 put_user(tsize, &ct->u.user.target_size))
469 return -EFAULT;
470
471 if (target->compat_to_user) {
472 if (target->compat_to_user((void __user *)ct->data, t->data))
473 return -EFAULT;
474 } else {
475 if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct)))
476 return -EFAULT;
454 } 477 }
455 return ret; 478
479 *size -= off;
480 *dstptr += tsize;
481 return 0;
456} 482}
457EXPORT_SYMBOL_GPL(xt_compat_target); 483EXPORT_SYMBOL_GPL(xt_compat_target_to_user);
458#endif 484#endif
459 485
460struct xt_table_info *xt_alloc_table_info(unsigned int size) 486struct xt_table_info *xt_alloc_table_info(unsigned int size)