Skip to content

Commit c3d03e8

Browse files
committed
KEYS: asymmetric: Copy sig and digest in public_key_verify_signature()
Commit ac4e97a ("scatterlist: sg_set_buf() argument must be in linear mapping") checks that both the signature and the digest reside in the linear mapping area. However, more recently commit ba14a19 ("fork: Add generic vmalloced stack support") made it possible to move the stack in the vmalloc area, which is not contiguous, and thus not suitable for sg_set_buf() which needs adjacent pages. Always make a copy of the signature and digest in the same buffer used to store the key and its parameters, and pass them to sg_init_one(). Prefer it to conditionally doing the copy if necessary, to keep the code simple. The buffer allocated with kmalloc() is in the linear mapping area. Cc: [email protected] # 4.9.x Fixes: ba14a19 ("fork: Add generic vmalloced stack support") Link: https://lore.kernel.org/linux-integrity/[email protected]/ Suggested-by: Eric Biggers <[email protected]> Signed-off-by: Roberto Sassu <[email protected]> Reviewed-by: Eric Biggers <[email protected]> Tested-by: Stefan Berger <[email protected]>
1 parent 921bdc7 commit c3d03e8

File tree

1 file changed

+21
-17
lines changed

1 file changed

+21
-17
lines changed

crypto/asymmetric_keys/public_key.c

+21-17
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,10 @@ int public_key_verify_signature(const struct public_key *pkey,
380380
struct crypto_wait cwait;
381381
struct crypto_akcipher *tfm;
382382
struct akcipher_request *req;
383-
struct scatterlist src_sg[2];
383+
struct scatterlist src_sg;
384384
char alg_name[CRYPTO_MAX_ALG_NAME];
385-
char *key, *ptr;
385+
char *buf, *ptr;
386+
size_t buf_len;
386387
int ret;
387388

388389
pr_devel("==>%s()\n", __func__);
@@ -420,43 +421,46 @@ int public_key_verify_signature(const struct public_key *pkey,
420421
if (!req)
421422
goto error_free_tfm;
422423

423-
key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
424-
GFP_KERNEL);
425-
if (!key)
424+
buf_len = max_t(size_t, pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
425+
sig->s_size + sig->digest_size);
426+
427+
buf = kmalloc(buf_len, GFP_KERNEL);
428+
if (!buf)
426429
goto error_free_req;
427430

428-
memcpy(key, pkey->key, pkey->keylen);
429-
ptr = key + pkey->keylen;
431+
memcpy(buf, pkey->key, pkey->keylen);
432+
ptr = buf + pkey->keylen;
430433
ptr = pkey_pack_u32(ptr, pkey->algo);
431434
ptr = pkey_pack_u32(ptr, pkey->paramlen);
432435
memcpy(ptr, pkey->params, pkey->paramlen);
433436

434437
if (pkey->key_is_private)
435-
ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
438+
ret = crypto_akcipher_set_priv_key(tfm, buf, pkey->keylen);
436439
else
437-
ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
440+
ret = crypto_akcipher_set_pub_key(tfm, buf, pkey->keylen);
438441
if (ret)
439-
goto error_free_key;
442+
goto error_free_buf;
440443

441444
if (strcmp(pkey->pkey_algo, "sm2") == 0 && sig->data_size) {
442445
ret = cert_sig_digest_update(sig, tfm);
443446
if (ret)
444-
goto error_free_key;
447+
goto error_free_buf;
445448
}
446449

447-
sg_init_table(src_sg, 2);
448-
sg_set_buf(&src_sg[0], sig->s, sig->s_size);
449-
sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
450-
akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
450+
memcpy(buf, sig->s, sig->s_size);
451+
memcpy(buf + sig->s_size, sig->digest, sig->digest_size);
452+
453+
sg_init_one(&src_sg, buf, sig->s_size + sig->digest_size);
454+
akcipher_request_set_crypt(req, &src_sg, NULL, sig->s_size,
451455
sig->digest_size);
452456
crypto_init_wait(&cwait);
453457
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
454458
CRYPTO_TFM_REQ_MAY_SLEEP,
455459
crypto_req_done, &cwait);
456460
ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
457461

458-
error_free_key:
459-
kfree(key);
462+
error_free_buf:
463+
kfree(buf);
460464
error_free_req:
461465
akcipher_request_free(req);
462466
error_free_tfm:

0 commit comments

Comments
 (0)