diff options
| author | David S. Miller <davem@davemloft.net> | 2017-11-08 20:58:35 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-11-08 20:58:35 -0500 |
| commit | 6a17280247458ac2c302200e2d6ae36656f75bc6 (patch) | |
| tree | 1063ef6609bf185e13de668e07156e795d9cafb4 | |
| parent | 623859ae06b85cabba79ce78f0d49e67783d4c34 (diff) | |
| parent | c9f3f813d462c72dbe412cee6a5cbacf13c4ad5e (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says:
====================
pull request (net): ipsec 2017-11-09
1) Fix a use after free due to a reallocated skb head.
From Florian Westphal.
2) Fix sporadic lookup failures on labeled IPSEC.
From Florian Westphal.
3) Fix a stack out of bounds when a socket policy is applied
to an IPv6 socket that sends IPv4 packets.
Please pull or let me know if there are problems.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | net/xfrm/xfrm_input.c | 4 | ||||
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 71 |
2 files changed, 37 insertions, 38 deletions
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 82d20ee34581..347ab31574d5 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
| @@ -266,8 +266,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
| 266 | goto lock; | 266 | goto lock; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | daddr = (xfrm_address_t *)(skb_network_header(skb) + | ||
| 270 | XFRM_SPI_SKB_CB(skb)->daddroff); | ||
| 271 | family = XFRM_SPI_SKB_CB(skb)->family; | 269 | family = XFRM_SPI_SKB_CB(skb)->family; |
| 272 | 270 | ||
| 273 | /* if tunnel is present override skb->mark value with tunnel i_key */ | 271 | /* if tunnel is present override skb->mark value with tunnel i_key */ |
| @@ -294,6 +292,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
| 294 | goto drop; | 292 | goto drop; |
| 295 | } | 293 | } |
| 296 | 294 | ||
| 295 | daddr = (xfrm_address_t *)(skb_network_header(skb) + | ||
| 296 | XFRM_SPI_SKB_CB(skb)->daddroff); | ||
| 297 | do { | 297 | do { |
| 298 | if (skb->sp->len == XFRM_MAX_DEPTH) { | 298 | if (skb->sp->len == XFRM_MAX_DEPTH) { |
| 299 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); | 299 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 8cafb3c0a4ac..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) { |
| @@ -1787,19 +1780,23 @@ void xfrm_policy_cache_flush(void) | |||
| 1787 | put_online_cpus(); | 1780 | put_online_cpus(); |
| 1788 | } | 1781 | } |
| 1789 | 1782 | ||
| 1790 | static bool xfrm_pol_dead(struct xfrm_dst *xdst) | 1783 | static bool xfrm_xdst_can_reuse(struct xfrm_dst *xdst, |
| 1784 | struct xfrm_state * const xfrm[], | ||
| 1785 | int num) | ||
| 1791 | { | 1786 | { |
| 1792 | unsigned int num_pols = xdst->num_pols; | 1787 | const struct dst_entry *dst = &xdst->u.dst; |
| 1793 | unsigned int pol_dead = 0, i; | 1788 | int i; |
| 1794 | 1789 | ||
| 1795 | for (i = 0; i < num_pols; i++) | 1790 | if (xdst->num_xfrms != num) |
| 1796 | pol_dead |= xdst->pols[i]->walk.dead; | 1791 | return false; |
| 1797 | 1792 | ||
| 1798 | /* Mark DST_OBSOLETE_DEAD to fail the next xfrm_dst_check() */ | 1793 | for (i = 0; i < num; i++) { |
| 1799 | if (pol_dead) | 1794 | if (!dst || dst->xfrm != xfrm[i]) |
| 1800 | xdst->u.dst.obsolete = DST_OBSOLETE_DEAD; | 1795 | return false; |
| 1796 | dst = dst->child; | ||
| 1797 | } | ||
| 1801 | 1798 | ||
| 1802 | return pol_dead; | 1799 | return xfrm_bundle_ok(xdst); |
| 1803 | } | 1800 | } |
| 1804 | 1801 | ||
| 1805 | static struct xfrm_dst * | 1802 | static struct xfrm_dst * |
| @@ -1813,26 +1810,28 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, | |||
| 1813 | struct dst_entry *dst; | 1810 | struct dst_entry *dst; |
| 1814 | int err; | 1811 | int err; |
| 1815 | 1812 | ||
| 1813 | /* Try to instantiate a bundle */ | ||
| 1814 | err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family); | ||
| 1815 | if (err <= 0) { | ||
| 1816 | if (err != 0 && err != -EAGAIN) | ||
| 1817 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); | ||
| 1818 | return ERR_PTR(err); | ||
| 1819 | } | ||
| 1820 | |||
| 1816 | xdst = this_cpu_read(xfrm_last_dst); | 1821 | xdst = this_cpu_read(xfrm_last_dst); |
| 1817 | if (xdst && | 1822 | if (xdst && |
| 1818 | xdst->u.dst.dev == dst_orig->dev && | 1823 | xdst->u.dst.dev == dst_orig->dev && |
| 1819 | xdst->num_pols == num_pols && | 1824 | xdst->num_pols == num_pols && |
| 1820 | !xfrm_pol_dead(xdst) && | ||
| 1821 | memcmp(xdst->pols, pols, | 1825 | memcmp(xdst->pols, pols, |
| 1822 | sizeof(struct xfrm_policy *) * num_pols) == 0 && | 1826 | sizeof(struct xfrm_policy *) * num_pols) == 0 && |
| 1823 | xfrm_bundle_ok(xdst)) { | 1827 | xfrm_xdst_can_reuse(xdst, xfrm, err)) { |
| 1824 | dst_hold(&xdst->u.dst); | 1828 | dst_hold(&xdst->u.dst); |
| 1829 | while (err > 0) | ||
| 1830 | xfrm_state_put(xfrm[--err]); | ||
| 1825 | return xdst; | 1831 | return xdst; |
| 1826 | } | 1832 | } |
| 1827 | 1833 | ||
| 1828 | old = xdst; | 1834 | old = xdst; |
| 1829 | /* Try to instantiate a bundle */ | ||
| 1830 | err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family); | ||
| 1831 | if (err <= 0) { | ||
| 1832 | if (err != 0 && err != -EAGAIN) | ||
| 1833 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); | ||
| 1834 | return ERR_PTR(err); | ||
| 1835 | } | ||
| 1836 | 1835 | ||
| 1837 | dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig); | 1836 | dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig); |
| 1838 | if (IS_ERR(dst)) { | 1837 | if (IS_ERR(dst)) { |
