diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/xfrm/xfrm_user.c | 50 |
1 files changed, 42 insertions, 8 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 6f97665983d2..311205ffa775 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -858,7 +858,6 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, | |||
858 | int i; | 858 | int i; |
859 | 859 | ||
860 | xp->xfrm_nr = nr; | 860 | xp->xfrm_nr = nr; |
861 | xp->family = ut->family; | ||
862 | for (i = 0; i < nr; i++, ut++) { | 861 | for (i = 0; i < nr; i++, ut++) { |
863 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; | 862 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; |
864 | 863 | ||
@@ -876,19 +875,53 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, | |||
876 | } | 875 | } |
877 | } | 876 | } |
878 | 877 | ||
878 | static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) | ||
879 | { | ||
880 | int i; | ||
881 | |||
882 | if (nr > XFRM_MAX_DEPTH) | ||
883 | return -EINVAL; | ||
884 | |||
885 | for (i = 0; i < nr; i++) { | ||
886 | /* We never validated the ut->family value, so many | ||
887 | * applications simply leave it at zero. The check was | ||
888 | * never made and ut->family was ignored because all | ||
889 | * templates could be assumed to have the same family as | ||
890 | * the policy itself. Now that we will have ipv4-in-ipv6 | ||
891 | * and ipv6-in-ipv4 tunnels, this is no longer true. | ||
892 | */ | ||
893 | if (!ut[i].family) | ||
894 | ut[i].family = family; | ||
895 | |||
896 | switch (ut[i].family) { | ||
897 | case AF_INET: | ||
898 | break; | ||
899 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
900 | case AF_INET6: | ||
901 | break; | ||
902 | #endif | ||
903 | default: | ||
904 | return -EINVAL; | ||
905 | }; | ||
906 | } | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
879 | static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) | 911 | static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) |
880 | { | 912 | { |
881 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; | 913 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; |
882 | struct xfrm_user_tmpl *utmpl; | ||
883 | int nr; | ||
884 | 914 | ||
885 | if (!rt) { | 915 | if (!rt) { |
886 | pol->xfrm_nr = 0; | 916 | pol->xfrm_nr = 0; |
887 | } else { | 917 | } else { |
888 | nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); | 918 | struct xfrm_user_tmpl *utmpl = RTA_DATA(rt); |
919 | int nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl); | ||
920 | int err; | ||
889 | 921 | ||
890 | if (nr > XFRM_MAX_DEPTH) | 922 | err = validate_tmpl(nr, utmpl, pol->family); |
891 | return -EINVAL; | 923 | if (err) |
924 | return err; | ||
892 | 925 | ||
893 | copy_templates(pol, RTA_DATA(rt), nr); | 926 | copy_templates(pol, RTA_DATA(rt), nr); |
894 | } | 927 | } |
@@ -1530,7 +1563,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xf | |||
1530 | } | 1563 | } |
1531 | 1564 | ||
1532 | /* build an XP */ | 1565 | /* build an XP */ |
1533 | xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { | 1566 | xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); |
1567 | if (!xp) { | ||
1534 | kfree(x); | 1568 | kfree(x); |
1535 | return err; | 1569 | return err; |
1536 | } | 1570 | } |
@@ -1979,7 +2013,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, | |||
1979 | return NULL; | 2013 | return NULL; |
1980 | 2014 | ||
1981 | nr = ((len - sizeof(*p)) / sizeof(*ut)); | 2015 | nr = ((len - sizeof(*p)) / sizeof(*ut)); |
1982 | if (nr > XFRM_MAX_DEPTH) | 2016 | if (validate_tmpl(nr, ut, p->sel.family)) |
1983 | return NULL; | 2017 | return NULL; |
1984 | 2018 | ||
1985 | if (p->dir > XFRM_POLICY_OUT) | 2019 | if (p->dir > XFRM_POLICY_OUT) |