summaryrefslogtreecommitdiffstats
path: root/net/key
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2023-05-09 11:00:06 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-05-24 17:32:43 +0100
commit474d57adf16ac6322fed2f87cdbc277280742106 (patch)
treebcf04bfd441447ba2918e85568f353ed18ee1008 /net/key
parente5a0b280b05fd1d4172f9742215401e3099d5876 (diff)
downloadlinux-stable-474d57adf16ac6322fed2f87cdbc277280742106.tar.gz
linux-stable-474d57adf16ac6322fed2f87cdbc277280742106.tar.bz2
linux-stable-474d57adf16ac6322fed2f87cdbc277280742106.zip
af_key: Reject optional tunnel/BEET mode templates in outbound policies
[ Upstream commit cf3128a7aca55b2eefb68281d44749c683bdc96f ] xfrm_state_find() uses `encap_family` of the current template with the passed local and remote addresses to find a matching state. If an optional tunnel or BEET mode template is skipped in a mixed-family scenario, there could be a mismatch causing an out-of-bounds read as the addresses were not replaced to match the family of the next template. While there are theoretical use cases for optional templates in outbound policies, the only practical one is to skip IPComp states in inbound policies if uncompressed packets are received that are handled by an implicitly created IPIP state instead. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Tobias Brunner <tobias@strongswan.org> Acked-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net/key')
-rw-r--r--net/key/af_key.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 95edcbedf6ef..8c21de50eadf 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1940,7 +1940,8 @@ static u32 gen_reqid(struct net *net)
}
static int
-parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
+parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_policy *pol,
+ struct sadb_x_ipsecrequest *rq)
{
struct net *net = xp_net(xp);
struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr;
@@ -1958,9 +1959,12 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0)
return -EINVAL;
t->mode = mode;
- if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE)
+ if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE) {
+ if ((mode == XFRM_MODE_TUNNEL || mode == XFRM_MODE_BEET) &&
+ pol->sadb_x_policy_dir == IPSEC_DIR_OUTBOUND)
+ return -EINVAL;
t->optional = 1;
- else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
+ } else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
t->reqid = rq->sadb_x_ipsecrequest_reqid;
if (t->reqid > IPSEC_MANUAL_REQID_MAX)
t->reqid = 0;
@@ -2002,7 +2006,7 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
rq->sadb_x_ipsecrequest_len < sizeof(*rq))
return -EINVAL;
- if ((err = parse_ipsecrequest(xp, rq)) < 0)
+ if ((err = parse_ipsecrequest(xp, pol, rq)) < 0)
return err;
len -= rq->sadb_x_ipsecrequest_len;
rq = (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len);