aspeed/hace: Fix mapped address may not be unmapped issue
In the do_hash_operation, the code may be returned earlier because hash_prepare_sg_iov or hash_prepare_direct_iov may return a failure. When this condition is happened, current code flow doesn't go through later code segments. Finally, it causes the mapped address isn't unmapped properly. This change unmaps any mapped addresses when an error occurs, preventing a resource leak. Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com> Reviewed-by: Jamin Lin <jamin_lin@aspeedtech.com> Link: https://lore.kernel.org/qemu-devel/20260512065002.1516704-2-kane_chen@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
Kane Chen committed
May 12, 2026 at 06:50 UTC
bf6df3e02175412090f7e9ecec664a6e7fc5aa7d
1 file changed
+45
-18
hw/misc/aspeed_hace.c
+45
-18
@@ -218,8 +218,19 @@ static bool hash_accumulate_len(AspeedHACEState *s, hwaddr plen)
218
return true;
219
}
220
221
+static void hash_iov_unmap(AspeedHACEState *s, struct iovec *iov,
222
+ hwaddr *mapped_lens, int iov_count)
223
+{
224
+ for (; iov_count > 0; iov_count--) {
225
+ address_space_unmap(&s->dram_as, iov[iov_count - 1].iov_base,
226
+ mapped_lens[iov_count - 1], false,
227
+ mapped_lens[iov_count - 1]);
228
+ }
229
+}
230
+
231
static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov,
222
- bool acc_mode, bool *acc_final_request)
232
+ bool acc_mode, bool *acc_final_request,
233
+ hwaddr *mapped_lens)
234
{
235
uint32_t total_msg_len;
236
uint32_t pad_offset;
@@ -243,9 +254,11 @@ static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov,
254
255
iov[0].iov_base = haddr;
256
iov_idx = 1;
257
+ mapped_lens[0] = plen;
258
259
if (acc_mode) {
260
if (!hash_accumulate_len(s, plen)) {
261
+ hash_iov_unmap(s, iov, mapped_lens, 1);
262
return -1;
263
}
264
@@ -265,7 +278,8 @@ static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov,
278
}
279
280
static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov,
268
- bool acc_mode, bool *acc_final_request)
281
+ bool acc_mode, bool *acc_final_request,
282
+ hwaddr *mapped_lens)
283
{
284
uint32_t total_msg_len;
285
uint32_t pad_offset;
@@ -275,6 +289,7 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov,
289
int iov_idx;
290
hwaddr plen;
291
void *haddr;
292
+ int iov_mapped = 0;
293
294
src = hash_get_source_addr(s);
295
for (iov_idx = 0; !(len & SG_LIST_LEN_LAST); iov_idx++) {
@@ -282,7 +297,7 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov,
297
qemu_log_mask(LOG_GUEST_ERROR,
298
"%s: Failed to set end of sg list marker\n",
299
__func__);
285
- return -1;
300
+ goto fail;
301
}
302
303
len = address_space_ldl_le(&s->dram_as, src,
@@ -307,15 +322,17 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov,
322
"%s: Unable to map address, sg_addr=0x%x, "
323
"plen=0x%" HWADDR_PRIx "\n",
324
__func__, sg_addr, plen);
310
- return -1;
325
+ goto fail;
326
}
327
328
src += SG_LIST_ENTRY_SIZE;
329
330
iov[iov_idx].iov_base = haddr;
331
+ iov_mapped = iov_idx + 1;
332
+ mapped_lens[iov_idx] = plen;
333
if (acc_mode) {
334
if (!hash_accumulate_len(s, plen)) {
318
- return -1;
335
+ goto fail;
336
}
337
338
if (has_padding(s, &iov[iov_idx], plen, &total_msg_len,
@@ -332,6 +349,10 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov,
349
}
350
351
return iov_idx;
352
+
353
+fail:
354
+ hash_iov_unmap(s, iov, mapped_lens, iov_mapped);
355
+ return -1;
356
}
357
358
static uint64_t hash_get_digest_addr(AspeedHACEState *s)
@@ -350,6 +371,7 @@ static uint64_t hash_get_digest_addr(AspeedHACEState *s)
371
static void hash_write_digest_and_unmap_iov(AspeedHACEState *s,
372
struct iovec *iov,
373
int iov_idx,
374
+ hwaddr *mapped_lens,
375
uint8_t *digest_buf,
376
size_t digest_len)
377
{
@@ -369,15 +391,12 @@ static void hash_write_digest_and_unmap_iov(AspeedHACEState *s,
391
hace_hexdump("digest", (char *)digest_buf, digest_len);
392
}
393
372
- for (; iov_idx > 0; iov_idx--) {
373
- address_space_unmap(&s->dram_as, iov[iov_idx - 1].iov_base,
374
- iov[iov_idx - 1].iov_len, false,
375
- iov[iov_idx - 1].iov_len);
376
- }
394
+ hash_iov_unmap(s, iov, mapped_lens, iov_idx);
395
}
396
397
static void hash_execute_non_acc_mode(AspeedHACEState *s, int algo,
380
- struct iovec *iov, int iov_idx)
398
+ struct iovec *iov, int iov_idx,
399
+ hwaddr *mapped_lens)
400
{
401
g_autofree uint8_t *digest_buf = NULL;
402
Error *local_err = NULL;
@@ -389,15 +408,17 @@ static void hash_execute_non_acc_mode(AspeedHACEState *s, int algo,
408
"%s: qcrypto hash bytesv failed : %s",
409
__func__, error_get_pretty(local_err));
410
error_free(local_err);
411
+ hash_iov_unmap(s, iov, mapped_lens, iov_idx);
412
return;
413
}
414
395
- hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, digest_len);
415
+ hash_write_digest_and_unmap_iov(s, iov, iov_idx, mapped_lens,
416
+ digest_buf, digest_len);
417
}
418
419
static void hash_execute_acc_mode(AspeedHACEState *s, int algo,
420
struct iovec *iov, int iov_idx,
400
- bool final_request)
421
+ bool final_request, hwaddr *mapped_lens)
422
{
423
g_autofree uint8_t *digest_buf = NULL;
424
Error *local_err = NULL;
@@ -411,6 +432,7 @@ static void hash_execute_acc_mode(AspeedHACEState *s, int algo,
432
qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto hash new failed : %s",
433
__func__, error_get_pretty(local_err));
434
error_free(local_err);
435
+ hash_iov_unmap(s, iov, mapped_lens, iov_idx);
436
return;
437
}
438
}
@@ -419,6 +441,7 @@ static void hash_execute_acc_mode(AspeedHACEState *s, int algo,
441
qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto hash updatev failed : %s",
442
__func__, error_get_pretty(local_err));
443
error_free(local_err);
444
+ hash_iov_unmap(s, iov, mapped_lens, iov_idx);
445
return;
446
}
447
@@ -438,22 +461,25 @@ static void hash_execute_acc_mode(AspeedHACEState *s, int algo,
461
s->total_req_len = 0;
462
}
463
441
- hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, digest_len);
464
+ hash_write_digest_and_unmap_iov(s, iov, iov_idx, mapped_lens,
465
+ digest_buf, digest_len);
466
}
467
468
static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
469
bool acc_mode)
470
{
471
QEMU_UNINITIALIZED struct iovec iov[ASPEED_HACE_MAX_SG];
472
+ hwaddr mapped_lens[ASPEED_HACE_MAX_SG] = { 0 };
473
bool acc_final_request = false;
474
int iov_idx = -1;
475
476
/* Prepares the iov for hashing operations based on the selected mode */
477
if (sg_mode) {
453
- iov_idx = hash_prepare_sg_iov(s, iov, acc_mode, &acc_final_request);
478
+ iov_idx = hash_prepare_sg_iov(s, iov, acc_mode, &acc_final_request,
479
+ mapped_lens);
480
} else {
481
iov_idx = hash_prepare_direct_iov(s, iov, acc_mode,
456
- &acc_final_request);
482
+ &acc_final_request, mapped_lens);
483
}
484
485
if (iov_idx <= 0) {
@@ -468,9 +494,10 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
494
495
/* Executes the hash operation */
496
if (acc_mode) {
471
- hash_execute_acc_mode(s, algo, iov, iov_idx, acc_final_request);
497
+ hash_execute_acc_mode(s, algo, iov, iov_idx, acc_final_request,
498
+ mapped_lens);
499
} else {
473
- hash_execute_non_acc_mode(s, algo, iov, iov_idx);
500
+ hash_execute_non_acc_mode(s, algo, iov, iov_idx, mapped_lens);
501
}
502
}
503