fill_buf_random() writes the entire guest-requested amount of random
bytes in one go. Since the length is a full 64-bit value, a guest can
request several gigabytes and keep the vCPU spinning inside the helper,
without a chance to react to interrupts.
Do the same thing as HELPER(mvcl): check cpu_loop_exit_requested() at the
bottom of the loop, and when a return to the main loop is pending, stop
and report partial completion with condition code 3.
Reported-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Fixes: 3dbc5fdacb5a ("target/s390x: support PRNO_TRNG instruction")
Cc: qemu-stable@nongnu.org
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
target/s390x/tcg/crypto_helper.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
index 8fe0a222198..6a5dbe1cafa 100644
--- a/target/s390x/tcg/crypto_helper.c
+++ b/target/s390x/tcg/crypto_helper.c
@@ -16,6 +16,7 @@
#include "qemu/guest-random.h"
#include "s390x-internal.h"
#include "tcg_s390x.h"
+#include "exec/cpu-common.h"
#include "exec/helper-proto.h"
#include "accel/tcg/cpu-ldst-common.h"
#include "accel/tcg/cpu-mmu-index.h"
@@ -242,8 +243,8 @@ static int cpacf_sha512(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
return !len ? 0 : 3;
}
-static void fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
- uint64_t *buf_reg, uint64_t *len_reg)
+static int fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
+ uint64_t *buf_reg, uint64_t *len_reg)
{
const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
uint8_t tmp[256];
@@ -265,7 +266,13 @@ static void fill_buf_random(CPUS390XState *env, const int mmu_idx, uintptr_t ra,
--*len_reg;
}
len -= block;
+
+ if (cpu_loop_exit_requested(env_cpu(env))) {
+ break;
+ }
}
+
+ return len == 0 ? 0 : 3;
}
uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
@@ -278,6 +285,7 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
uint8_t subfunc[16] = { 0 };
uint64_t param_addr;
MemOpIdx oi;
+ int cc;
switch (type) {
case S390_FEAT_TYPE_KMAC:
@@ -308,9 +316,13 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
return cpacf_sha512(env, mmu_idx, ra, env->regs[1], &env->regs[r2],
&env->regs[r2 + 1], type);
case 114: /* CPACF_PRNO_TRNG */
- fill_buf_random(env, mmu_idx, ra, &env->regs[r1], &env->regs[r1 + 1]);
- fill_buf_random(env, mmu_idx, ra, &env->regs[r2], &env->regs[r2 + 1]);
- break;
+ cc = fill_buf_random(env, mmu_idx, ra,
+ &env->regs[r1], &env->regs[r1 + 1]);
+ if (cc == 0) {
+ cc = fill_buf_random(env, mmu_idx, ra,
+ &env->regs[r2], &env->regs[r2 + 1]);
+ }
+ return cc;
default:
/* we don't implement any other subfunction yet */
g_assert_not_reached();
--
2.55.0
On 2026-07-14 21:17, Ilya Leoshkevich wrote:
> fill_buf_random() writes the entire guest-requested amount of random
> bytes in one go. Since the length is a full 64-bit value, a guest can
> request several gigabytes and keep the vCPU spinning inside the helper,
> without a chance to react to interrupts.
>
> Do the same thing as HELPER(mvcl): check cpu_loop_exit_requested() at
> the
> bottom of the loop, and when a return to the main loop is pending, stop
> and report partial completion with condition code 3.
>
> Reported-by: Christian Borntraeger <borntraeger@linux.ibm.com>
> Fixes: 3dbc5fdacb5a ("target/s390x: support PRNO_TRNG instruction")
> Cc: qemu-stable@nongnu.org
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> ---
> target/s390x/tcg/crypto_helper.c | 22 +++++++++++++++++-----
> 1 file changed, 17 insertions(+), 5 deletions(-)
>
> diff --git a/target/s390x/tcg/crypto_helper.c
> b/target/s390x/tcg/crypto_helper.c
> index 8fe0a222198..6a5dbe1cafa 100644
> --- a/target/s390x/tcg/crypto_helper.c
> +++ b/target/s390x/tcg/crypto_helper.c
> @@ -16,6 +16,7 @@
> #include "qemu/guest-random.h"
> #include "s390x-internal.h"
> #include "tcg_s390x.h"
> +#include "exec/cpu-common.h"
> #include "exec/helper-proto.h"
> #include "accel/tcg/cpu-ldst-common.h"
> #include "accel/tcg/cpu-mmu-index.h"
> @@ -242,8 +243,8 @@ static int cpacf_sha512(CPUS390XState *env, const
> int mmu_idx, uintptr_t ra,
> return !len ? 0 : 3;
> }
>
> -static void fill_buf_random(CPUS390XState *env, const int mmu_idx,
> uintptr_t ra,
> - uint64_t *buf_reg, uint64_t *len_reg)
> +static int fill_buf_random(CPUS390XState *env, const int mmu_idx,
> uintptr_t ra,
> + uint64_t *buf_reg, uint64_t *len_reg)
> {
> const MemOpIdx oi = make_memop_idx(MO_8, mmu_idx);
> uint8_t tmp[256];
> @@ -265,7 +266,13 @@ static void fill_buf_random(CPUS390XState *env,
> const int mmu_idx, uintptr_t ra,
> --*len_reg;
> }
> len -= block;
> +
> + if (cpu_loop_exit_requested(env_cpu(env))) {
> + break;
> + }
> }
> +
> + return len == 0 ? 0 : 3;
> }
>
> uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2,
> uint32_t r3,
> @@ -278,6 +285,7 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t
> r1, uint32_t r2, uint32_t r3,
> uint8_t subfunc[16] = { 0 };
> uint64_t param_addr;
> MemOpIdx oi;
> + int cc;
>
> switch (type) {
> case S390_FEAT_TYPE_KMAC:
> @@ -308,9 +316,13 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t
> r1, uint32_t r2, uint32_t r3,
> return cpacf_sha512(env, mmu_idx, ra, env->regs[1],
> &env->regs[r2],
> &env->regs[r2 + 1], type);
> case 114: /* CPACF_PRNO_TRNG */
> - fill_buf_random(env, mmu_idx, ra, &env->regs[r1],
> &env->regs[r1 + 1]);
> - fill_buf_random(env, mmu_idx, ra, &env->regs[r2],
> &env->regs[r2 + 1]);
> - break;
> + cc = fill_buf_random(env, mmu_idx, ra,
> + &env->regs[r1], &env->regs[r1 + 1]);
> + if (cc == 0) {
> + cc = fill_buf_random(env, mmu_idx, ra,
> + &env->regs[r2], &env->regs[r2 + 1]);
> + }
> + return cc;
> default:
> /* we don't implement any other subfunction yet */
> g_assert_not_reached();
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
© 2016 - 2026 Red Hat, Inc.