Commit 4b66af2d authored by Kevin Easton's avatar Kevin Easton Committed by Steffen Klassert

af_key: Always verify length of provided sadb_key

Key extensions (struct sadb_key) include a user-specified number of key
bits.  The kernel uses that number to determine how much key data to copy
out of the message in pfkey_msg2xfrm_state().

The length of the sadb_key message must be verified to be long enough,
even in the case of SADB_X_AALG_NULL.  Furthermore, the sadb_key_len value
must be long enough to include both the key data and the struct sadb_key
itself.

Introduce a helper function verify_key_len(), and call it from
parse_exthdrs() where other exthdr types are similarly checked for
correctness.
Signed-off-by: default avatarKevin Easton <kevin@guarana.org>
Reported-by: syzbot+5022a34ca5a3d49b84223653fab632dfb7b4cf37@syzkaller.appspotmail.com
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 76327a35
...@@ -437,6 +437,24 @@ static int verify_address_len(const void *p) ...@@ -437,6 +437,24 @@ static int verify_address_len(const void *p)
return 0; return 0;
} }
static inline int sadb_key_len(const struct sadb_key *key)
{
int key_bytes = DIV_ROUND_UP(key->sadb_key_bits, 8);
return DIV_ROUND_UP(sizeof(struct sadb_key) + key_bytes,
sizeof(uint64_t));
}
static int verify_key_len(const void *p)
{
const struct sadb_key *key = p;
if (sadb_key_len(key) > key->sadb_key_len)
return -EINVAL;
return 0;
}
static inline int pfkey_sec_ctx_len(const struct sadb_x_sec_ctx *sec_ctx) static inline int pfkey_sec_ctx_len(const struct sadb_x_sec_ctx *sec_ctx)
{ {
return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) + return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) +
...@@ -533,16 +551,25 @@ static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void * ...@@ -533,16 +551,25 @@ static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void *
return -EINVAL; return -EINVAL;
if (ext_hdrs[ext_type-1] != NULL) if (ext_hdrs[ext_type-1] != NULL)
return -EINVAL; return -EINVAL;
if (ext_type == SADB_EXT_ADDRESS_SRC || switch (ext_type) {
ext_type == SADB_EXT_ADDRESS_DST || case SADB_EXT_ADDRESS_SRC:
ext_type == SADB_EXT_ADDRESS_PROXY || case SADB_EXT_ADDRESS_DST:
ext_type == SADB_X_EXT_NAT_T_OA) { case SADB_EXT_ADDRESS_PROXY:
case SADB_X_EXT_NAT_T_OA:
if (verify_address_len(p)) if (verify_address_len(p))
return -EINVAL; return -EINVAL;
} break;
if (ext_type == SADB_X_EXT_SEC_CTX) { case SADB_X_EXT_SEC_CTX:
if (verify_sec_ctx_len(p)) if (verify_sec_ctx_len(p))
return -EINVAL; return -EINVAL;
break;
case SADB_EXT_KEY_AUTH:
case SADB_EXT_KEY_ENCRYPT:
if (verify_key_len(p))
return -EINVAL;
break;
default:
break;
} }
ext_hdrs[ext_type-1] = (void *) p; ext_hdrs[ext_type-1] = (void *) p;
} }
...@@ -1104,14 +1131,12 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, ...@@ -1104,14 +1131,12 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
key = ext_hdrs[SADB_EXT_KEY_AUTH - 1]; key = ext_hdrs[SADB_EXT_KEY_AUTH - 1];
if (key != NULL && if (key != NULL &&
sa->sadb_sa_auth != SADB_X_AALG_NULL && sa->sadb_sa_auth != SADB_X_AALG_NULL &&
((key->sadb_key_bits+7) / 8 == 0 || key->sadb_key_bits == 0)
(key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];
if (key != NULL && if (key != NULL &&
sa->sadb_sa_encrypt != SADB_EALG_NULL && sa->sadb_sa_encrypt != SADB_EALG_NULL &&
((key->sadb_key_bits+7) / 8 == 0 || key->sadb_key_bits == 0)
(key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
x = xfrm_state_alloc(net); x = xfrm_state_alloc(net);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment