aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/x_tables.h4
-rw-r--r--net/ipv4/netfilter/arp_tables.c5
-rw-r--r--net/ipv4/netfilter/ip_tables.c5
-rw-r--r--net/ipv6/netfilter/ip6_tables.c5
-rw-r--r--net/netfilter/x_tables.c17
5 files changed, 26 insertions, 10 deletions
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 08de48bbe92e..30cfb1e943fb 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -242,7 +242,7 @@ void xt_unregister_match(struct xt_match *target);
242int xt_register_matches(struct xt_match *match, unsigned int n); 242int xt_register_matches(struct xt_match *match, unsigned int n);
243void xt_unregister_matches(struct xt_match *match, unsigned int n); 243void xt_unregister_matches(struct xt_match *match, unsigned int n);
244 244
245int xt_check_entry_offsets(const void *base, 245int xt_check_entry_offsets(const void *base, const char *elems,
246 unsigned int target_offset, 246 unsigned int target_offset,
247 unsigned int next_offset); 247 unsigned int next_offset);
248 248
@@ -494,7 +494,7 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
494 unsigned int *size); 494 unsigned int *size);
495int xt_compat_target_to_user(const struct xt_entry_target *t, 495int xt_compat_target_to_user(const struct xt_entry_target *t,
496 void __user **dstptr, unsigned int *size); 496 void __user **dstptr, unsigned int *size);
497int xt_compat_check_entry_offsets(const void *base, 497int xt_compat_check_entry_offsets(const void *base, const char *elems,
498 unsigned int target_offset, 498 unsigned int target_offset,
499 unsigned int next_offset); 499 unsigned int next_offset);
500 500
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index ab8952a49bfa..95ed4e454c60 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -592,7 +592,8 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
592 if (!arp_checkentry(&e->arp)) 592 if (!arp_checkentry(&e->arp))
593 return -EINVAL; 593 return -EINVAL;
594 594
595 err = xt_check_entry_offsets(e, e->target_offset, e->next_offset); 595 err = xt_check_entry_offsets(e, e->elems, e->target_offset,
596 e->next_offset);
596 if (err) 597 if (err)
597 return err; 598 return err;
598 599
@@ -1254,7 +1255,7 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
1254 if (!arp_checkentry(&e->arp)) 1255 if (!arp_checkentry(&e->arp))
1255 return -EINVAL; 1256 return -EINVAL;
1256 1257
1257 ret = xt_compat_check_entry_offsets(e, e->target_offset, 1258 ret = xt_compat_check_entry_offsets(e, e->elems, e->target_offset,
1258 e->next_offset); 1259 e->next_offset);
1259 if (ret) 1260 if (ret)
1260 return ret; 1261 return ret;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 7d24c872723f..baab033d74e0 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -754,7 +754,8 @@ check_entry_size_and_hooks(struct ipt_entry *e,
754 if (!ip_checkentry(&e->ip)) 754 if (!ip_checkentry(&e->ip))
755 return -EINVAL; 755 return -EINVAL;
756 756
757 err = xt_check_entry_offsets(e, e->target_offset, e->next_offset); 757 err = xt_check_entry_offsets(e, e->elems, e->target_offset,
758 e->next_offset);
758 if (err) 759 if (err)
759 return err; 760 return err;
760 761
@@ -1513,7 +1514,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
1513 if (!ip_checkentry(&e->ip)) 1514 if (!ip_checkentry(&e->ip))
1514 return -EINVAL; 1515 return -EINVAL;
1515 1516
1516 ret = xt_compat_check_entry_offsets(e, 1517 ret = xt_compat_check_entry_offsets(e, e->elems,
1517 e->target_offset, e->next_offset); 1518 e->target_offset, e->next_offset);
1518 if (ret) 1519 if (ret)
1519 return ret; 1520 return ret;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 73eee7b5fd60..6957627c7931 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -766,7 +766,8 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
766 if (!ip6_checkentry(&e->ipv6)) 766 if (!ip6_checkentry(&e->ipv6))
767 return -EINVAL; 767 return -EINVAL;
768 768
769 err = xt_check_entry_offsets(e, e->target_offset, e->next_offset); 769 err = xt_check_entry_offsets(e, e->elems, e->target_offset,
770 e->next_offset);
770 if (err) 771 if (err)
771 return err; 772 return err;
772 773
@@ -1525,7 +1526,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1525 if (!ip6_checkentry(&e->ipv6)) 1526 if (!ip6_checkentry(&e->ipv6))
1526 return -EINVAL; 1527 return -EINVAL;
1527 1528
1528 ret = xt_compat_check_entry_offsets(e, 1529 ret = xt_compat_check_entry_offsets(e, e->elems,
1529 e->target_offset, e->next_offset); 1530 e->target_offset, e->next_offset);
1530 if (ret) 1531 if (ret)
1531 return ret; 1532 return ret;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 1cb7a271c024..e2a6f2a9051b 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -546,14 +546,17 @@ struct compat_xt_standard_target {
546 compat_uint_t verdict; 546 compat_uint_t verdict;
547}; 547};
548 548
549/* see xt_check_entry_offsets */ 549int xt_compat_check_entry_offsets(const void *base, const char *elems,
550int xt_compat_check_entry_offsets(const void *base,
551 unsigned int target_offset, 550 unsigned int target_offset,
552 unsigned int next_offset) 551 unsigned int next_offset)
553{ 552{
553 long size_of_base_struct = elems - (const char *)base;
554 const struct compat_xt_entry_target *t; 554 const struct compat_xt_entry_target *t;
555 const char *e = base; 555 const char *e = base;
556 556
557 if (target_offset < size_of_base_struct)
558 return -EINVAL;
559
557 if (target_offset + sizeof(*t) > next_offset) 560 if (target_offset + sizeof(*t) > next_offset)
558 return -EINVAL; 561 return -EINVAL;
559 562
@@ -577,12 +580,16 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets);
577 * xt_check_entry_offsets - validate arp/ip/ip6t_entry 580 * xt_check_entry_offsets - validate arp/ip/ip6t_entry
578 * 581 *
579 * @base: pointer to arp/ip/ip6t_entry 582 * @base: pointer to arp/ip/ip6t_entry
583 * @elems: pointer to first xt_entry_match, i.e. ip(6)t_entry->elems
580 * @target_offset: the arp/ip/ip6_t->target_offset 584 * @target_offset: the arp/ip/ip6_t->target_offset
581 * @next_offset: the arp/ip/ip6_t->next_offset 585 * @next_offset: the arp/ip/ip6_t->next_offset
582 * 586 *
583 * validates that target_offset and next_offset are sane. 587 * validates that target_offset and next_offset are sane.
584 * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. 588 * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version.
585 * 589 *
590 * This function does not validate the targets or matches themselves, it
591 * only tests that all the offsets and sizes are correct.
592 *
586 * The arp/ip/ip6t_entry structure @base must have passed following tests: 593 * The arp/ip/ip6t_entry structure @base must have passed following tests:
587 * - it must point to a valid memory location 594 * - it must point to a valid memory location
588 * - base to base + next_offset must be accessible, i.e. not exceed allocated 595 * - base to base + next_offset must be accessible, i.e. not exceed allocated
@@ -591,12 +598,18 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets);
591 * Return: 0 on success, negative errno on failure. 598 * Return: 0 on success, negative errno on failure.
592 */ 599 */
593int xt_check_entry_offsets(const void *base, 600int xt_check_entry_offsets(const void *base,
601 const char *elems,
594 unsigned int target_offset, 602 unsigned int target_offset,
595 unsigned int next_offset) 603 unsigned int next_offset)
596{ 604{
605 long size_of_base_struct = elems - (const char *)base;
597 const struct xt_entry_target *t; 606 const struct xt_entry_target *t;
598 const char *e = base; 607 const char *e = base;
599 608
609 /* target start is within the ip/ip6/arpt_entry struct */
610 if (target_offset < size_of_base_struct)
611 return -EINVAL;
612
600 if (target_offset + sizeof(*t) > next_offset) 613 if (target_offset + sizeof(*t) > next_offset)
601 return -EINVAL; 614 return -EINVAL;
602 615