diff options
author | Alejandro Zeise <alejandro.zeise@seagate.com> | 2024-08-07 19:51:22 +0000 |
---|---|---|
committer | Cédric Le Goater <clg@redhat.com> | 2024-10-24 07:57:47 +0200 |
commit | 4c1d0af4a28d15d04a9bd522a5c3976eda9f999e (patch) | |
tree | 847c88040cccf0680b2e2d4494948215b8c5f866 /hw/misc | |
parent | 34fdd734c5da7de39c09f3d8793042292f95dacc (diff) |
hw/misc/aspeed_hace: Fix SG Accumulative hashing
Make the Aspeed HACE module use the new qcrypto accumulative hashing functions
when in scatter-gather accumulative mode. A hash context will maintain a
"running-hash" as each scatter-gather chunk is received.
Previously each scatter-gather "chunk" was cached
so the hash could be computed once the final chunk was received.
However, the cache was a shallow copy, so once the guest overwrote the
memory provided to HACE the final hash would not be correct.
Possibly related to: https://gitlab.com/qemu-project/qemu/-/issues/1121
Buglink: https://github.com/openbmc/qemu/issues/36
Signed-off-by: Alejandro Zeise <alejandro.zeise@seagate.com>
[ clg: - Checkpatch fixes
- Reworked qcrypto_hash*() error reports in do_hash_operation() ]
Signed-off-by: Cédric Le Goater <clg@redhat.com>
Acked-by: Andrew Jeffery <andrew@codeconstruct.com.au>
Reviewed-by: Jamin Lin <jamin_lin@aspeedtech.com>
Reviewed-by: Joel Stanley <joel@jms.id.au>
Diffstat (limited to 'hw/misc')
-rw-r--r-- | hw/misc/aspeed_hace.c | 104 |
1 files changed, 59 insertions, 45 deletions
diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index b6f43f65b2..bc1d66ad80 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -1,6 +1,7 @@ /* * ASPEED Hash and Crypto Engine * + * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates * Copyright (C) 2021 IBM Corp. * * Joel Stanley <joel@jms.id.au> @@ -151,49 +152,28 @@ static int reconstruct_iov(AspeedHACEState *s, struct iovec *iov, int id, return iov_count; } -/** - * Generate iov for accumulative mode. - * - * @param s aspeed hace state object - * @param iov iov of the current request - * @param id index of the current iov - * @param req_len length of the current request - * - * @return count of iov - */ -static int gen_acc_mode_iov(AspeedHACEState *s, struct iovec *iov, int id, - hwaddr *req_len) -{ - uint32_t pad_offset; - uint32_t total_msg_len; - s->total_req_len += *req_len; - - if (has_padding(s, &iov[id], *req_len, &total_msg_len, &pad_offset)) { - if (s->iov_count) { - return reconstruct_iov(s, iov, id, &pad_offset); - } - - *req_len -= s->total_req_len - total_msg_len; - s->total_req_len = 0; - iov[id].iov_len = *req_len; - } else { - s->iov_cache[s->iov_count].iov_base = iov->iov_base; - s->iov_cache[s->iov_count].iov_len = *req_len; - ++s->iov_count; - } - - return id + 1; -} - static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, bool acc_mode) { struct iovec iov[ASPEED_HACE_MAX_SG]; + uint32_t total_msg_len; + uint32_t pad_offset; g_autofree uint8_t *digest_buf = NULL; size_t digest_len = 0; - int niov = 0; + bool sg_acc_mode_final_request = false; int i; void *haddr; + Error *local_err = NULL; + + if (acc_mode && s->hash_ctx == NULL) { + s->hash_ctx = qcrypto_hash_new(algo, &local_err); + if (s->hash_ctx == NULL) { + qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash failed : %s", + error_get_pretty(local_err)); + error_free(local_err); + return; + } + } if (sg_mode) { uint32_t len = 0; @@ -226,8 +206,16 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, } iov[i].iov_base = haddr; if (acc_mode) { - niov = gen_acc_mode_iov(s, iov, i, &plen); - + s->total_req_len += plen; + + if (has_padding(s, &iov[i], plen, &total_msg_len, + &pad_offset)) { + /* Padding being present indicates the final request */ + sg_acc_mode_final_request = true; + iov[i].iov_len = pad_offset; + } else { + iov[i].iov_len = plen; + } } else { iov[i].iov_len = plen; } @@ -252,21 +240,42 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, * required to check whether cache is empty. If no, we should * combine cached iov and the current iov. */ - uint32_t total_msg_len; - uint32_t pad_offset; s->total_req_len += len; if (has_padding(s, iov, len, &total_msg_len, &pad_offset)) { - niov = reconstruct_iov(s, iov, 0, &pad_offset); + i = reconstruct_iov(s, iov, 0, &pad_offset); } } } - if (niov) { - i = niov; - } + if (acc_mode) { + if (qcrypto_hash_updatev(s->hash_ctx, iov, i, &local_err) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash update failed : %s", + error_get_pretty(local_err)); + error_free(local_err); + return; + } + + if (sg_acc_mode_final_request) { + if (qcrypto_hash_finalize_bytes(s->hash_ctx, &digest_buf, + &digest_len, &local_err)) { + qemu_log_mask(LOG_GUEST_ERROR, + "qcrypto hash finalize failed : %s", + error_get_pretty(local_err)); + error_free(local_err); + local_err = NULL; + } - if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); + qcrypto_hash_free(s->hash_ctx); + + s->hash_ctx = NULL; + s->iov_count = 0; + s->total_req_len = 0; + } + } else if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, + &digest_len, &local_err) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash bytesv failed : %s", + error_get_pretty(local_err)); + error_free(local_err); return; } @@ -397,6 +406,11 @@ static void aspeed_hace_reset(DeviceState *dev) { struct AspeedHACEState *s = ASPEED_HACE(dev); + if (s->hash_ctx != NULL) { + qcrypto_hash_free(s->hash_ctx); + s->hash_ctx = NULL; + } + memset(s->regs, 0, sizeof(s->regs)); s->iov_count = 0; s->total_req_len = 0; |