aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorThomas Egerer <thomas.egerer@secunet.com>2010-09-20 14:11:38 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-20 14:11:38 -0400
commit8444cf712c5f71845cba9dc30d8f530ff0d5ff83 (patch)
tree3283983551829eb3f985a92d49ec65ac8e487268 /net
parent842c74bffcdb1d305ccd9e61e417cceae86b9963 (diff)
xfrm: Allow different selector family in temporary state
The family parameter xfrm_state_find is used to find a state matching a certain policy. This value is set to the template's family (encap_family) right before xfrm_state_find is called. The family parameter is however also used to construct a temporary state in xfrm_state_find itself which is wrong for inter-family scenarios because it produces a selector for the wrong family. Since this selector is included in the xfrm_user_acquire structure, user space programs misinterpret IPv6 addresses as IPv4 and vice versa. This patch splits up the original init_tempsel function into a part that initializes the selector respectively the props and id of the temporary state, to allow for differing ip address families whithin the state. Signed-off-by: Thomas Egerer <thomas.egerer@secunet.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/xfrm4_state.c33
-rw-r--r--net/ipv6/xfrm6_state.c33
-rw-r--r--net/xfrm/xfrm_policy.c5
-rw-r--r--net/xfrm/xfrm_state.c45
4 files changed, 67 insertions, 49 deletions
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 1ef1366a0a03..47947624eccc 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -21,21 +21,25 @@ static int xfrm4_init_flags(struct xfrm_state *x)
21} 21}
22 22
23static void 23static void
24__xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, 24__xfrm4_init_tempsel(struct xfrm_selector *sel, struct flowi *fl)
25 struct xfrm_tmpl *tmpl, 25{
26 xfrm_address_t *daddr, xfrm_address_t *saddr) 26 sel->daddr.a4 = fl->fl4_dst;
27 sel->saddr.a4 = fl->fl4_src;
28 sel->dport = xfrm_flowi_dport(fl);
29 sel->dport_mask = htons(0xffff);
30 sel->sport = xfrm_flowi_sport(fl);
31 sel->sport_mask = htons(0xffff);
32 sel->family = AF_INET;
33 sel->prefixlen_d = 32;
34 sel->prefixlen_s = 32;
35 sel->proto = fl->proto;
36 sel->ifindex = fl->oif;
37}
38
39static void
40xfrm4_init_temprop(struct xfrm_state *x, struct xfrm_tmpl *tmpl,
41 xfrm_address_t *daddr, xfrm_address_t *saddr)
27{ 42{
28 x->sel.daddr.a4 = fl->fl4_dst;
29 x->sel.saddr.a4 = fl->fl4_src;
30 x->sel.dport = xfrm_flowi_dport(fl);
31 x->sel.dport_mask = htons(0xffff);
32 x->sel.sport = xfrm_flowi_sport(fl);
33 x->sel.sport_mask = htons(0xffff);
34 x->sel.family = AF_INET;
35 x->sel.prefixlen_d = 32;
36 x->sel.prefixlen_s = 32;
37 x->sel.proto = fl->proto;
38 x->sel.ifindex = fl->oif;
39 x->id = tmpl->id; 43 x->id = tmpl->id;
40 if (x->id.daddr.a4 == 0) 44 if (x->id.daddr.a4 == 0)
41 x->id.daddr.a4 = daddr->a4; 45 x->id.daddr.a4 = daddr->a4;
@@ -70,6 +74,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
70 .owner = THIS_MODULE, 74 .owner = THIS_MODULE,
71 .init_flags = xfrm4_init_flags, 75 .init_flags = xfrm4_init_flags,
72 .init_tempsel = __xfrm4_init_tempsel, 76 .init_tempsel = __xfrm4_init_tempsel,
77 .init_temprop = xfrm4_init_temprop,
73 .output = xfrm4_output, 78 .output = xfrm4_output,
74 .extract_input = xfrm4_extract_input, 79 .extract_input = xfrm4_extract_input,
75 .extract_output = xfrm4_extract_output, 80 .extract_output = xfrm4_extract_output,
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index f417b77fa0e1..a67575d472a3 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -20,23 +20,27 @@
20#include <net/addrconf.h> 20#include <net/addrconf.h>
21 21
22static void 22static void
23__xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, 23__xfrm6_init_tempsel(struct xfrm_selector *sel, struct flowi *fl)
24 struct xfrm_tmpl *tmpl,
25 xfrm_address_t *daddr, xfrm_address_t *saddr)
26{ 24{
27 /* Initialize temporary selector matching only 25 /* Initialize temporary selector matching only
28 * to current session. */ 26 * to current session. */
29 ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst); 27 ipv6_addr_copy((struct in6_addr *)&sel->daddr, &fl->fl6_dst);
30 ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src); 28 ipv6_addr_copy((struct in6_addr *)&sel->saddr, &fl->fl6_src);
31 x->sel.dport = xfrm_flowi_dport(fl); 29 sel->dport = xfrm_flowi_dport(fl);
32 x->sel.dport_mask = htons(0xffff); 30 sel->dport_mask = htons(0xffff);
33 x->sel.sport = xfrm_flowi_sport(fl); 31 sel->sport = xfrm_flowi_sport(fl);
34 x->sel.sport_mask = htons(0xffff); 32 sel->sport_mask = htons(0xffff);
35 x->sel.family = AF_INET6; 33 sel->family = AF_INET6;
36 x->sel.prefixlen_d = 128; 34 sel->prefixlen_d = 128;
37 x->sel.prefixlen_s = 128; 35 sel->prefixlen_s = 128;
38 x->sel.proto = fl->proto; 36 sel->proto = fl->proto;
39 x->sel.ifindex = fl->oif; 37 sel->ifindex = fl->oif;
38}
39
40static void
41xfrm6_init_temprop(struct xfrm_state *x, struct xfrm_tmpl *tmpl,
42 xfrm_address_t *daddr, xfrm_address_t *saddr)
43{
40 x->id = tmpl->id; 44 x->id = tmpl->id;
41 if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) 45 if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
42 memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); 46 memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
@@ -168,6 +172,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
168 .eth_proto = htons(ETH_P_IPV6), 172 .eth_proto = htons(ETH_P_IPV6),
169 .owner = THIS_MODULE, 173 .owner = THIS_MODULE,
170 .init_tempsel = __xfrm6_init_tempsel, 174 .init_tempsel = __xfrm6_init_tempsel,
175 .init_temprop = xfrm6_init_temprop,
171 .tmpl_sort = __xfrm6_tmpl_sort, 176 .tmpl_sort = __xfrm6_tmpl_sort,
172 .state_sort = __xfrm6_state_sort, 177 .state_sort = __xfrm6_state_sort,
173 .output = xfrm6_output, 178 .output = xfrm6_output,
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 2b3ed7ad4933..cbab6e1a8c9c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1175,9 +1175,8 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
1175 tmpl->mode == XFRM_MODE_BEET) { 1175 tmpl->mode == XFRM_MODE_BEET) {
1176 remote = &tmpl->id.daddr; 1176 remote = &tmpl->id.daddr;
1177 local = &tmpl->saddr; 1177 local = &tmpl->saddr;
1178 family = tmpl->encap_family; 1178 if (xfrm_addr_any(local, tmpl->encap_family)) {
1179 if (xfrm_addr_any(local, family)) { 1179 error = xfrm_get_saddr(net, &tmp, remote, tmpl->encap_family);
1180 error = xfrm_get_saddr(net, &tmp, remote, family);
1181 if (error) 1180 if (error)
1182 goto fail; 1181 goto fail;
1183 local = &tmp; 1182 local = &tmp;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 5208b12fbfb4..eb96ce52f178 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -656,15 +656,23 @@ void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si)
656EXPORT_SYMBOL(xfrm_sad_getinfo); 656EXPORT_SYMBOL(xfrm_sad_getinfo);
657 657
658static int 658static int
659xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, 659xfrm_init_tempstate(struct xfrm_state *x, struct flowi *fl,
660 struct xfrm_tmpl *tmpl, 660 struct xfrm_tmpl *tmpl,
661 xfrm_address_t *daddr, xfrm_address_t *saddr, 661 xfrm_address_t *daddr, xfrm_address_t *saddr,
662 unsigned short family) 662 unsigned short family)
663{ 663{
664 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 664 struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
665 if (!afinfo) 665 if (!afinfo)
666 return -1; 666 return -1;
667 afinfo->init_tempsel(x, fl, tmpl, daddr, saddr); 667 afinfo->init_tempsel(&x->sel, fl);
668
669 if (family != tmpl->encap_family) {
670 xfrm_state_put_afinfo(afinfo);
671 afinfo = xfrm_state_get_afinfo(tmpl->encap_family);
672 if (!afinfo)
673 return -1;
674 }
675 afinfo->init_temprop(x, tmpl, daddr, saddr);
668 xfrm_state_put_afinfo(afinfo); 676 xfrm_state_put_afinfo(afinfo);
669 return 0; 677 return 0;
670} 678}
@@ -790,37 +798,38 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
790 int error = 0; 798 int error = 0;
791 struct xfrm_state *best = NULL; 799 struct xfrm_state *best = NULL;
792 u32 mark = pol->mark.v & pol->mark.m; 800 u32 mark = pol->mark.v & pol->mark.m;
801 unsigned short encap_family = tmpl->encap_family;
793 802
794 to_put = NULL; 803 to_put = NULL;
795 804
796 spin_lock_bh(&xfrm_state_lock); 805 spin_lock_bh(&xfrm_state_lock);
797 h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, family); 806 h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
798 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { 807 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
799 if (x->props.family == family && 808 if (x->props.family == encap_family &&
800 x->props.reqid == tmpl->reqid && 809 x->props.reqid == tmpl->reqid &&
801 (mark & x->mark.m) == x->mark.v && 810 (mark & x->mark.m) == x->mark.v &&
802 !(x->props.flags & XFRM_STATE_WILDRECV) && 811 !(x->props.flags & XFRM_STATE_WILDRECV) &&
803 xfrm_state_addr_check(x, daddr, saddr, family) && 812 xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
804 tmpl->mode == x->props.mode && 813 tmpl->mode == x->props.mode &&
805 tmpl->id.proto == x->id.proto && 814 tmpl->id.proto == x->id.proto &&
806 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 815 (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
807 xfrm_state_look_at(pol, x, fl, family, daddr, saddr, 816 xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr,
808 &best, &acquire_in_progress, &error); 817 &best, &acquire_in_progress, &error);
809 } 818 }
810 if (best) 819 if (best)
811 goto found; 820 goto found;
812 821
813 h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family); 822 h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
814 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { 823 hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) {
815 if (x->props.family == family && 824 if (x->props.family == encap_family &&
816 x->props.reqid == tmpl->reqid && 825 x->props.reqid == tmpl->reqid &&
817 (mark & x->mark.m) == x->mark.v && 826 (mark & x->mark.m) == x->mark.v &&
818 !(x->props.flags & XFRM_STATE_WILDRECV) && 827 !(x->props.flags & XFRM_STATE_WILDRECV) &&
819 xfrm_state_addr_check(x, daddr, saddr, family) && 828 xfrm_state_addr_check(x, daddr, saddr, encap_family) &&
820 tmpl->mode == x->props.mode && 829 tmpl->mode == x->props.mode &&
821 tmpl->id.proto == x->id.proto && 830 tmpl->id.proto == x->id.proto &&
822 (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 831 (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
823 xfrm_state_look_at(pol, x, fl, family, daddr, saddr, 832 xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr,
824 &best, &acquire_in_progress, &error); 833 &best, &acquire_in_progress, &error);
825 } 834 }
826 835
@@ -829,7 +838,7 @@ found:
829 if (!x && !error && !acquire_in_progress) { 838 if (!x && !error && !acquire_in_progress) {
830 if (tmpl->id.spi && 839 if (tmpl->id.spi &&
831 (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, 840 (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi,
832 tmpl->id.proto, family)) != NULL) { 841 tmpl->id.proto, encap_family)) != NULL) {
833 to_put = x0; 842 to_put = x0;
834 error = -EEXIST; 843 error = -EEXIST;
835 goto out; 844 goto out;
@@ -839,9 +848,9 @@ found:
839 error = -ENOMEM; 848 error = -ENOMEM;
840 goto out; 849 goto out;
841 } 850 }
842 /* Initialize temporary selector matching only 851 /* Initialize temporary state matching only
843 * to current session. */ 852 * to current session. */
844 xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); 853 xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family);
845 memcpy(&x->mark, &pol->mark, sizeof(x->mark)); 854 memcpy(&x->mark, &pol->mark, sizeof(x->mark));
846 855
847 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); 856 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
@@ -856,10 +865,10 @@ found:
856 x->km.state = XFRM_STATE_ACQ; 865 x->km.state = XFRM_STATE_ACQ;
857 list_add(&x->km.all, &net->xfrm.state_all); 866 list_add(&x->km.all, &net->xfrm.state_all);
858 hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); 867 hlist_add_head(&x->bydst, net->xfrm.state_bydst+h);
859 h = xfrm_src_hash(net, daddr, saddr, family); 868 h = xfrm_src_hash(net, daddr, saddr, encap_family);
860 hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h); 869 hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
861 if (x->id.spi) { 870 if (x->id.spi) {
862 h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, family); 871 h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
863 hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); 872 hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
864 } 873 }
865 x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 874 x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;