Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Kevin Easton <kevin@guarana.org>
Reported-by: syzbot+5022a34ca5a3d49b84223653fab632dfb7b4cf37@syzkaller.appspotmail.com
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>

authored by

Kevin Easton and committed by
Steffen Klassert
4b66af2d 76327a35

+35 -10
+35 -10
net/key/af_key.c
··· 437 437 return 0; 438 438 } 439 439 440 + static inline int sadb_key_len(const struct sadb_key *key) 441 + { 442 + int key_bytes = DIV_ROUND_UP(key->sadb_key_bits, 8); 443 + 444 + return DIV_ROUND_UP(sizeof(struct sadb_key) + key_bytes, 445 + sizeof(uint64_t)); 446 + } 447 + 448 + static int verify_key_len(const void *p) 449 + { 450 + const struct sadb_key *key = p; 451 + 452 + if (sadb_key_len(key) > key->sadb_key_len) 453 + return -EINVAL; 454 + 455 + return 0; 456 + } 457 + 440 458 static inline int pfkey_sec_ctx_len(const struct sadb_x_sec_ctx *sec_ctx) 441 459 { 442 460 return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) + ··· 551 533 return -EINVAL; 552 534 if (ext_hdrs[ext_type-1] != NULL) 553 535 return -EINVAL; 554 - if (ext_type == SADB_EXT_ADDRESS_SRC || 555 - ext_type == SADB_EXT_ADDRESS_DST || 556 - ext_type == SADB_EXT_ADDRESS_PROXY || 557 - ext_type == SADB_X_EXT_NAT_T_OA) { 536 + switch (ext_type) { 537 + case SADB_EXT_ADDRESS_SRC: 538 + case SADB_EXT_ADDRESS_DST: 539 + case SADB_EXT_ADDRESS_PROXY: 540 + case SADB_X_EXT_NAT_T_OA: 558 541 if (verify_address_len(p)) 559 542 return -EINVAL; 560 - } 561 - if (ext_type == SADB_X_EXT_SEC_CTX) { 543 + break; 544 + case SADB_X_EXT_SEC_CTX: 562 545 if (verify_sec_ctx_len(p)) 563 546 return -EINVAL; 547 + break; 548 + case SADB_EXT_KEY_AUTH: 549 + case SADB_EXT_KEY_ENCRYPT: 550 + if (verify_key_len(p)) 551 + return -EINVAL; 552 + break; 553 + default: 554 + break; 564 555 } 565 556 ext_hdrs[ext_type-1] = (void *) p; 566 557 } ··· 1131 1104 key = ext_hdrs[SADB_EXT_KEY_AUTH - 1]; 1132 1105 if (key != NULL && 1133 1106 sa->sadb_sa_auth != SADB_X_AALG_NULL && 1134 - ((key->sadb_key_bits+7) / 8 == 0 || 1135 - (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) 1107 + key->sadb_key_bits == 0) 1136 1108 return ERR_PTR(-EINVAL); 1137 1109 key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; 1138 1110 if (key != NULL && 1139 1111 sa->sadb_sa_encrypt != SADB_EALG_NULL && 1140 - ((key->sadb_key_bits+7) / 8 == 0 || 1141 - (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) 1112 + key->sadb_key_bits == 0) 1142 1113 return ERR_PTR(-EINVAL); 1143 1114 1144 1115 x = xfrm_state_alloc(net);