@samitouri / QOSamiQemu / commits / bf6df3e021

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