[PATCH v2 1/2] target/s390x: Make PRNO TRNG interruptible

Ilya Leoshkevich posted 2 patches 2 months ago
Maintainers: Richard Henderson <richard.henderson@linaro.org>, Ilya Leoshkevich <iii@linux.ibm.com>, David Hildenbrand <david@kernel.org>, Cornelia Huck <cohuck@redhat.com>, Eric Farman <farman@linux.ibm.com>, Matthew Rosato <mjrosato@linux.ibm.com>
[PATCH v2 1/2] target/s390x: Make PRNO TRNG interruptible
Posted by Ilya Leoshkevich 2 months ago
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
Re: [PATCH v2 1/2] target/s390x: Make PRNO TRNG interruptible
Posted by Harald Freudenberger 1 month, 3 weeks ago
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>