Commit b698a9f4 authored by Gary R Hook's avatar Gary R Hook Committed by Herbert Xu

crypto: ccp - Validate buffer lengths for copy operations

The CCP driver copies data between scatter/gather lists and DMA buffers.
The length of the requested copy operation must be checked against
the available destination buffer length.
Reported-by: default avatarMaciej S. Szmigiero <mail@maciej.szmigiero.name>
Signed-off-by: default avatarGary R Hook <gary.hook@amd.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 3d053d53
...@@ -178,14 +178,18 @@ static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa, ...@@ -178,14 +178,18 @@ static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa,
return 0; return 0;
} }
static void ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset, static int ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
struct scatterlist *sg, unsigned int sg_offset, struct scatterlist *sg, unsigned int sg_offset,
unsigned int len) unsigned int len)
{ {
WARN_ON(!wa->address); WARN_ON(!wa->address);
if (len > (wa->length - wa_offset))
return -EINVAL;
scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len, scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
0); 0);
return 0;
} }
static void ccp_get_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset, static void ccp_get_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
...@@ -205,8 +209,11 @@ static int ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa, ...@@ -205,8 +209,11 @@ static int ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa,
unsigned int len) unsigned int len)
{ {
u8 *p, *q; u8 *p, *q;
int rc;
ccp_set_dm_area(wa, wa_offset, sg, sg_offset, len); rc = ccp_set_dm_area(wa, wa_offset, sg, sg_offset, len);
if (rc)
return rc;
p = wa->address + wa_offset; p = wa->address + wa_offset;
q = p + len - 1; q = p + len - 1;
...@@ -509,7 +516,9 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -509,7 +516,9 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
return ret; return ret;
dm_offset = CCP_SB_BYTES - aes->key_len; dm_offset = CCP_SB_BYTES - aes->key_len;
ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len); ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
if (ret)
goto e_key;
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key, ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_256BIT); CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) { if (ret) {
...@@ -528,7 +537,9 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -528,7 +537,9 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
goto e_key; goto e_key;
dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE; dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len); ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
if (ret)
goto e_ctx;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT); CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) { if (ret) {
...@@ -556,8 +567,10 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -556,8 +567,10 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
goto e_src; goto e_src;
} }
ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0, ret = ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0,
aes->cmac_key_len); aes->cmac_key_len);
if (ret)
goto e_src;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT); CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) { if (ret) {
...@@ -666,7 +679,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -666,7 +679,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
return ret; return ret;
dm_offset = CCP_SB_BYTES - aes->key_len; dm_offset = CCP_SB_BYTES - aes->key_len;
ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len); ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
if (ret)
goto e_key;
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key, ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_256BIT); CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) { if (ret) {
...@@ -685,7 +700,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -685,7 +700,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
goto e_key; goto e_key;
dm_offset = CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES - aes->iv_len; dm_offset = CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES - aes->iv_len;
ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len); ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
if (ret)
goto e_ctx;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT); CCP_PASSTHRU_BYTESWAP_256BIT);
...@@ -777,7 +794,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -777,7 +794,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
goto e_dst; goto e_dst;
} }
ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len); ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
if (ret)
goto e_dst;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT); CCP_PASSTHRU_BYTESWAP_256BIT);
...@@ -820,7 +839,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -820,7 +839,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
DMA_BIDIRECTIONAL); DMA_BIDIRECTIONAL);
if (ret) if (ret)
goto e_tag; goto e_tag;
ccp_set_dm_area(&tag, 0, p_tag, 0, AES_BLOCK_SIZE); ret = ccp_set_dm_area(&tag, 0, p_tag, 0, AES_BLOCK_SIZE);
if (ret)
goto e_tag;
ret = memcmp(tag.address, final_wa.address, AES_BLOCK_SIZE); ret = memcmp(tag.address, final_wa.address, AES_BLOCK_SIZE);
ccp_dm_free(&tag); ccp_dm_free(&tag);
...@@ -914,7 +935,9 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) ...@@ -914,7 +935,9 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
return ret; return ret;
dm_offset = CCP_SB_BYTES - aes->key_len; dm_offset = CCP_SB_BYTES - aes->key_len;
ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len); ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
if (ret)
goto e_key;
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key, ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_256BIT); CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) { if (ret) {
...@@ -935,7 +958,9 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) ...@@ -935,7 +958,9 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
if (aes->mode != CCP_AES_MODE_ECB) { if (aes->mode != CCP_AES_MODE_ECB) {
/* Load the AES context - convert to LE */ /* Load the AES context - convert to LE */
dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE; dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len); ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
if (ret)
goto e_ctx;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_256BIT); CCP_PASSTHRU_BYTESWAP_256BIT);
if (ret) { if (ret) {
...@@ -1113,8 +1138,12 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -1113,8 +1138,12 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
* big endian to little endian. * big endian to little endian.
*/ */
dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128; dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len); ret = ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len); if (ret)
goto e_key;
ret = ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len);
if (ret)
goto e_key;
} else { } else {
/* Version 5 CCPs use a 512-bit space for the key: each portion /* Version 5 CCPs use a 512-bit space for the key: each portion
* occupies 256 bits, or one entire slot, and is zero-padded. * occupies 256 bits, or one entire slot, and is zero-padded.
...@@ -1123,9 +1152,13 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -1123,9 +1152,13 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
dm_offset = CCP_SB_BYTES; dm_offset = CCP_SB_BYTES;
pad = dm_offset - xts->key_len; pad = dm_offset - xts->key_len;
ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len); ret = ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len);
ccp_set_dm_area(&key, dm_offset + pad, xts->key, xts->key_len, if (ret)
xts->key_len); goto e_key;
ret = ccp_set_dm_area(&key, dm_offset + pad, xts->key,
xts->key_len, xts->key_len);
if (ret)
goto e_key;
} }
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key, ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_256BIT); CCP_PASSTHRU_BYTESWAP_256BIT);
...@@ -1144,7 +1177,9 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -1144,7 +1177,9 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
if (ret) if (ret)
goto e_key; goto e_key;
ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len); ret = ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len);
if (ret)
goto e_ctx;
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
CCP_PASSTHRU_BYTESWAP_NOOP); CCP_PASSTHRU_BYTESWAP_NOOP);
if (ret) { if (ret) {
...@@ -1287,12 +1322,18 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) ...@@ -1287,12 +1322,18 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
dm_offset = CCP_SB_BYTES - des3->key_len; /* Basic offset */ dm_offset = CCP_SB_BYTES - des3->key_len; /* Basic offset */
len_singlekey = des3->key_len / 3; len_singlekey = des3->key_len / 3;
ccp_set_dm_area(&key, dm_offset + 2 * len_singlekey, ret = ccp_set_dm_area(&key, dm_offset + 2 * len_singlekey,
des3->key, 0, len_singlekey); des3->key, 0, len_singlekey);
ccp_set_dm_area(&key, dm_offset + len_singlekey, if (ret)
goto e_key;
ret = ccp_set_dm_area(&key, dm_offset + len_singlekey,
des3->key, len_singlekey, len_singlekey); des3->key, len_singlekey, len_singlekey);
ccp_set_dm_area(&key, dm_offset, if (ret)
goto e_key;
ret = ccp_set_dm_area(&key, dm_offset,
des3->key, 2 * len_singlekey, len_singlekey); des3->key, 2 * len_singlekey, len_singlekey);
if (ret)
goto e_key;
/* Copy the key to the SB */ /* Copy the key to the SB */
ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key, ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
...@@ -1320,7 +1361,10 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) ...@@ -1320,7 +1361,10 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
/* Load the context into the LSB */ /* Load the context into the LSB */
dm_offset = CCP_SB_BYTES - des3->iv_len; dm_offset = CCP_SB_BYTES - des3->iv_len;
ccp_set_dm_area(&ctx, dm_offset, des3->iv, 0, des3->iv_len); ret = ccp_set_dm_area(&ctx, dm_offset, des3->iv, 0,
des3->iv_len);
if (ret)
goto e_ctx;
if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
load_mode = CCP_PASSTHRU_BYTESWAP_NOOP; load_mode = CCP_PASSTHRU_BYTESWAP_NOOP;
...@@ -1604,8 +1648,10 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) ...@@ -1604,8 +1648,10 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
} }
} else { } else {
/* Restore the context */ /* Restore the context */
ccp_set_dm_area(&ctx, 0, sha->ctx, 0, ret = ccp_set_dm_area(&ctx, 0, sha->ctx, 0,
sb_count * CCP_SB_BYTES); sb_count * CCP_SB_BYTES);
if (ret)
goto e_ctx;
} }
ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
...@@ -1927,7 +1973,9 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, ...@@ -1927,7 +1973,9 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q,
if (ret) if (ret)
return ret; return ret;
ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len); ret = ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len);
if (ret)
goto e_mask;
ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key, ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
CCP_PASSTHRU_BYTESWAP_NOOP); CCP_PASSTHRU_BYTESWAP_NOOP);
if (ret) { if (ret) {
......
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