Skip to content

Commit cf3128a

Browse files
tobiasbrunnerklassert
authored andcommitted
af_key: Reject optional tunnel/BEET mode templates in outbound policies
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: 1da177e ("Linux-2.6.12-rc2") Signed-off-by: Tobias Brunner <[email protected]> Acked-by: Herbert Xu <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent 3d776e3 commit cf3128a

File tree

1 file changed

+8
-4
lines changed

1 file changed

+8
-4
lines changed

net/key/af_key.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,7 +1940,8 @@ static u32 gen_reqid(struct net *net)
19401940
}
19411941

19421942
static int
1943-
parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
1943+
parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_policy *pol,
1944+
struct sadb_x_ipsecrequest *rq)
19441945
{
19451946
struct net *net = xp_net(xp);
19461947
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)
19581959
if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0)
19591960
return -EINVAL;
19601961
t->mode = mode;
1961-
if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE)
1962+
if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE) {
1963+
if ((mode == XFRM_MODE_TUNNEL || mode == XFRM_MODE_BEET) &&
1964+
pol->sadb_x_policy_dir == IPSEC_DIR_OUTBOUND)
1965+
return -EINVAL;
19621966
t->optional = 1;
1963-
else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
1967+
} else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
19641968
t->reqid = rq->sadb_x_ipsecrequest_reqid;
19651969
if (t->reqid > IPSEC_MANUAL_REQID_MAX)
19661970
t->reqid = 0;
@@ -2002,7 +2006,7 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
20022006
rq->sadb_x_ipsecrequest_len < sizeof(*rq))
20032007
return -EINVAL;
20042008

2005-
if ((err = parse_ipsecrequest(xp, rq)) < 0)
2009+
if ((err = parse_ipsecrequest(xp, pol, rq)) < 0)
20062010
return err;
20072011
len -= rq->sadb_x_ipsecrequest_len;
20082012
rq = (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len);

0 commit comments

Comments
 (0)