aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2017-11-02 03:10:17 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2017-11-03 08:02:41 -0400
commitc9f3f813d462c72dbe412cee6a5cbacf13c4ad5e (patch)
tree5cf9469a3b411befeb91cfd3f34170b92e2a8356
parentcf37966751747727629fe51fd4a1d4edd8457c60 (diff)
xfrm: Fix stack-out-of-bounds read in xfrm_state_find.
When we do tunnel or beet mode, we pass saddr and daddr from the template to xfrm_state_find(), this is ok. On transport mode, we pass the addresses from the flowi, assuming that the IP addresses (and address family) don't change during transformation. This assumption is wrong in the IPv4 mapped IPv6 case, packet is IPv4 and template is IPv6. Fix this by using the addresses from the template unconditionally. Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r--net/xfrm/xfrm_policy.c29
1 files changed, 11 insertions, 18 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index a2e531bf4f97..6eb228a70131 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1361,36 +1361,29 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
1361 struct net *net = xp_net(policy); 1361 struct net *net = xp_net(policy);
1362 int nx; 1362 int nx;
1363 int i, error; 1363 int i, error;
1364 xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
1365 xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
1366 xfrm_address_t tmp; 1364 xfrm_address_t tmp;
1367 1365
1368 for (nx = 0, i = 0; i < policy->xfrm_nr; i++) { 1366 for (nx = 0, i = 0; i < policy->xfrm_nr; i++) {
1369 struct xfrm_state *x; 1367 struct xfrm_state *x;
1370 xfrm_address_t *remote = daddr; 1368 xfrm_address_t *local;
1371 xfrm_address_t *local = saddr; 1369 xfrm_address_t *remote;
1372 struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; 1370 struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
1373 1371
1374 if (tmpl->mode == XFRM_MODE_TUNNEL || 1372 remote = &tmpl->id.daddr;
1375 tmpl->mode == XFRM_MODE_BEET) { 1373 local = &tmpl->saddr;
1376 remote = &tmpl->id.daddr; 1374 if (xfrm_addr_any(local, tmpl->encap_family)) {
1377 local = &tmpl->saddr; 1375 error = xfrm_get_saddr(net, fl->flowi_oif,
1378 if (xfrm_addr_any(local, tmpl->encap_family)) { 1376 &tmp, remote,
1379 error = xfrm_get_saddr(net, fl->flowi_oif, 1377 tmpl->encap_family, 0);
1380 &tmp, remote, 1378 if (error)
1381 tmpl->encap_family, 0); 1379 goto fail;
1382 if (error) 1380 local = &tmp;
1383 goto fail;
1384 local = &tmp;
1385 }
1386 } 1381 }
1387 1382
1388 x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); 1383 x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
1389 1384
1390 if (x && x->km.state == XFRM_STATE_VALID) { 1385 if (x && x->km.state == XFRM_STATE_VALID) {
1391 xfrm[nx++] = x; 1386 xfrm[nx++] = x;
1392 daddr = remote;
1393 saddr = local;
1394 continue; 1387 continue;
1395 } 1388 }
1396 if (x) { 1389 if (x) {