All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
@ 2026-04-28  5:52 Kane Chen
  2026-04-28  5:52 ` [PATCH v1 1/1] " Kane Chen
  0 siblings, 1 reply; 10+ messages in thread
From: Kane Chen @ 2026-04-28  5:52 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
	Jamin Lin, Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Kane Chen

This series fixes a bounds issue in Aspeed OTP programming through the
Secure Boot Controller path.

The guest-provided OTP address is word-indexed in the SBC model, but
the OTP device write path operates on byte offsets. Passing the value
through without validation/conversion could lead to out-of-range writes.

The patch adds bounds checking in aspeed_sbc_otp_prog() before
converting the address to a byte offset, and aligns the OTP write
helper interfaces with byte-offset semantics.

The patch has been validated by a functional test and by the boundary
test documented at:
https://gitlab.com/qemu-project/qemu/-/work_items/3436

Kane-Chen-AS (1):
  hw/misc/aspeed_sbc: Add bounds checking for OTP write operations

 hw/misc/aspeed_sbc.c  | 14 +++++++++++---
 hw/nvram/aspeed_otp.c | 13 ++++++-------
 2 files changed, 17 insertions(+), 10 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-04-28  5:52 [PATCH v1 0/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations Kane Chen
@ 2026-04-28  5:52 ` Kane Chen
  2026-04-30 11:03   ` Peter Maydell
                     ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Kane Chen @ 2026-04-28  5:52 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell, Steven Lee, Troy Lee,
	Jamin Lin, Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, Kane Chen, qemu-stable@nongnu.org,
	Cédric Le Goater

There is a mismatch between the Aspeed OTP model and the Aspeed SBC
model in how the guest-provided address is handled.
aspeed_sbc_otp_prog() passes a word-indexed address directly
to address_space_write() without converting it to a byte offset,
whereas aspeed_otp_write() expects a byte offset and applies an
additional shift (otp_addr << 2). This double-shift confusion means
that an out-of-range word address can lead to a write beyond the
allocated storage.

Fix this by adding bounds checking on the word offset before
converting to byte offset and passing to address_space_write().
This matches the existing bounds check in aspeed_sbc_otp_read().

Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
Cc: qemu-stable@nongnu.org
Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller model")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3436
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Cédric Le Goater <clg@redhat.com>
Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
---
 hw/misc/aspeed_sbc.c  | 14 +++++++++++---
 hw/nvram/aspeed_otp.c | 13 ++++++-------
 2 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
index 065e822e70..8b74dca13c 100644
--- a/hw/misc/aspeed_sbc.c
+++ b/hw/misc/aspeed_sbc.c
@@ -159,13 +159,21 @@ static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
     MemTxResult ret;
     AspeedOTPState *otp = &s->otp;
     uint32_t value = s->regs[R_CAMP1];
+    uint32_t otp_offset = otp_addr << 2;
 
-    ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
-                        &value, sizeof(value));
+    if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Invalid OTP addr 0x%x\n",
+                      otp_addr);
+        return false;
+    }
+
+    ret = address_space_write(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
+                              &value, sizeof(value));
     if (ret != MEMTX_OK) {
         qemu_log_mask(LOG_GUEST_ERROR,
                       "Failed to write OTP memory, addr = %x\n",
-                      otp_addr);
+                      otp_offset);
         return false;
     }
 
diff --git a/hw/nvram/aspeed_otp.c b/hw/nvram/aspeed_otp.c
index a60289000c..1a9d3841b8 100644
--- a/hw/nvram/aspeed_otp.c
+++ b/hw/nvram/aspeed_otp.c
@@ -57,12 +57,12 @@ static bool valid_program_data(uint32_t otp_addr,
     return has_programmable_bits != 0;
 }
 
-static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
+static bool program_otpmem_data(void *opaque, hwaddr otp_offset,
                              uint32_t prog_bit, uint32_t *value)
 {
     AspeedOTPState *s = opaque;
+    uint32_t otp_addr = otp_offset >> 2;
     bool is_odd = otp_addr & 1;
-    uint32_t otp_offset = otp_addr << 2;
 
     memcpy(value, s->storage + otp_offset, sizeof(uint32_t));
 
@@ -79,26 +79,25 @@ static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
     return true;
 }
 
-static void aspeed_otp_write(void *opaque, hwaddr otp_addr,
+static void aspeed_otp_write(void *opaque, hwaddr otp_offset,
                                 uint64_t val, unsigned size)
 {
     AspeedOTPState *s = opaque;
-    uint32_t otp_offset, value;
+    uint32_t value;
 
-    if (!program_otpmem_data(s, otp_addr, val, &value)) {
+    if (!program_otpmem_data(s, otp_offset, val, &value)) {
         qemu_log_mask(LOG_GUEST_ERROR,
                       "%s: Failed to program data, value = %x, bit = %"PRIx64"\n",
                       __func__, value, val);
         return;
     }
 
-    otp_offset = otp_addr << 2;
     memcpy(s->storage + otp_offset, &value, size);
 
     if (s->blk) {
         if (blk_pwrite(s->blk, otp_offset, size, &value, 0) < 0) {
             qemu_log_mask(LOG_GUEST_ERROR,
-                          "%s: Failed to write %x to %x\n",
+                          "%s: Failed to write %x to %"HWADDR_PRIx"\n",
                           __func__, value, otp_offset);
 
             return;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-04-28  5:52 ` [PATCH v1 1/1] " Kane Chen
@ 2026-04-30 11:03   ` Peter Maydell
  2026-04-30 13:48     ` 回覆: " Kane Chen
  2026-04-30 17:56     ` Cédric Le Goater
  2026-04-30 17:26   ` Cédric Le Goater
  2026-05-14 18:48   ` Michael Tokarev
  2 siblings, 2 replies; 10+ messages in thread
From: Peter Maydell @ 2026-04-30 11:03 UTC (permalink / raw)
  To: Kane Chen
  Cc: Cédric Le Goater, Steven Lee, Troy Lee, Jamin Lin,
	Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
	open list:All patches CC here, Troy Lee, qemu-stable@nongnu.org,
	Cédric Le Goater

On Tue, 28 Apr 2026 at 06:53, Kane Chen <kane_chen@aspeedtech.com> wrote:
>
> There is a mismatch between the Aspeed OTP model and the Aspeed SBC
> model in how the guest-provided address is handled.
> aspeed_sbc_otp_prog() passes a word-indexed address directly
> to address_space_write() without converting it to a byte offset,
> whereas aspeed_otp_write() expects a byte offset and applies an
> additional shift (otp_addr << 2). This double-shift confusion means
> that an out-of-range word address can lead to a write beyond the
> allocated storage.
>
> Fix this by adding bounds checking on the word offset before
> converting to byte offset and passing to address_space_write().
> This matches the existing bounds check in aspeed_sbc_otp_read().
>
> Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
> Cc: qemu-stable@nongnu.org
> Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller model")
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3436
> Reported-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Cédric Le Goater <clg@redhat.com>
> Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
> ---
>  hw/misc/aspeed_sbc.c  | 14 +++++++++++---
>  hw/nvram/aspeed_otp.c | 13 ++++++-------
>  2 files changed, 17 insertions(+), 10 deletions(-)
>
> diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
> index 065e822e70..8b74dca13c 100644
> --- a/hw/misc/aspeed_sbc.c
> +++ b/hw/misc/aspeed_sbc.c
> @@ -159,13 +159,21 @@ static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
>      MemTxResult ret;
>      AspeedOTPState *otp = &s->otp;
>      uint32_t value = s->regs[R_CAMP1];
> +    uint32_t otp_offset = otp_addr << 2;
>
> -    ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
> -                        &value, sizeof(value));
> +    if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "Invalid OTP addr 0x%x\n",
> +                      otp_addr);
> +        return false;
> +    }
> +
> +    ret = address_space_write(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
> +                              &value, sizeof(value));
>      if (ret != MEMTX_OK) {
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "Failed to write OTP memory, addr = %x\n",
> -                      otp_addr);
> +                      otp_offset);

I would stick to reporting otp_addr here:
 - it's the value the guest actually writes
 - it matches the logging for "invalid OTP addr above"
 - it matches what aspeed_sbc_otp_read() logs in the equivalent case

Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 10+ messages in thread

* 回覆: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-04-30 11:03   ` Peter Maydell
@ 2026-04-30 13:48     ` Kane Chen
  2026-04-30 17:56     ` Cédric Le Goater
  1 sibling, 0 replies; 10+ messages in thread
From: Kane Chen @ 2026-04-30 13:48 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Cédric Le Goater, Steven Lee, Troy Lee, Jamin Lin,
	Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
	open list:All patches CC here, Troy Lee, qemu-stable@nongnu.org,
	Cédric Le Goater

[-- Attachment #1: Type: text/plain, Size: 3556 bytes --]

Hi Peter,

Thanks for your review and feedback. I will update the logging accordingly and submit a v2 patch.

Best Regards,
Kane
________________________________
寄件者: Peter Maydell <peter.maydell@linaro.org>
寄件日期: 2026年4月30日 下午 07:03
收件者: Kane Chen <kane_chen@aspeedtech.com>
副本: Cédric Le Goater <clg@kaod.org>; Steven Lee <steven_lee@aspeedtech.com>; Troy Lee <leetroy@gmail.com>; Jamin Lin <jamin_lin@aspeedtech.com>; Andrew Jeffery <andrew@codeconstruct.com.au>; Joel Stanley <joel@jms.id.au>; open list:ASPEED BMCs <qemu-arm@nongnu.org>; open list:All patches CC here <qemu-devel@nongnu.org>; Troy Lee <troy_lee@aspeedtech.com>; qemu-stable@nongnu.org <qemu-stable@nongnu.org>; Cédric Le Goater <clg@redhat.com>
主旨: Re: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations

On Tue, 28 Apr 2026 at 06:53, Kane Chen <kane_chen@aspeedtech.com> wrote:
>
> There is a mismatch between the Aspeed OTP model and the Aspeed SBC
> model in how the guest-provided address is handled.
> aspeed_sbc_otp_prog() passes a word-indexed address directly
> to address_space_write() without converting it to a byte offset,
> whereas aspeed_otp_write() expects a byte offset and applies an
> additional shift (otp_addr << 2). This double-shift confusion means
> that an out-of-range word address can lead to a write beyond the
> allocated storage.
>
> Fix this by adding bounds checking on the word offset before
> converting to byte offset and passing to address_space_write().
> This matches the existing bounds check in aspeed_sbc_otp_read().
>
> Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
> Cc: qemu-stable@nongnu.org
> Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller model")
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3436
> Reported-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Cédric Le Goater <clg@redhat.com>
> Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
> ---
>  hw/misc/aspeed_sbc.c  | 14 +++++++++++---
>  hw/nvram/aspeed_otp.c | 13 ++++++-------
>  2 files changed, 17 insertions(+), 10 deletions(-)
>
> diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
> index 065e822e70..8b74dca13c 100644
> --- a/hw/misc/aspeed_sbc.c
> +++ b/hw/misc/aspeed_sbc.c
> @@ -159,13 +159,21 @@ static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
>      MemTxResult ret;
>      AspeedOTPState *otp = &s->otp;
>      uint32_t value = s->regs[R_CAMP1];
> +    uint32_t otp_offset = otp_addr << 2;
>
> -    ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
> -                        &value, sizeof(value));
> +    if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "Invalid OTP addr 0x%x\n",
> +                      otp_addr);
> +        return false;
> +    }
> +
> +    ret = address_space_write(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
> +                              &value, sizeof(value));
>      if (ret != MEMTX_OK) {
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "Failed to write OTP memory, addr = %x\n",
> -                      otp_addr);
> +                      otp_offset);

I would stick to reporting otp_addr here:
 - it's the value the guest actually writes
 - it matches the logging for "invalid OTP addr above"
 - it matches what aspeed_sbc_otp_read() logs in the equivalent case

Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM

[-- Attachment #2: Type: text/html, Size: 6726 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-04-28  5:52 ` [PATCH v1 1/1] " Kane Chen
  2026-04-30 11:03   ` Peter Maydell
@ 2026-04-30 17:26   ` Cédric Le Goater
  2026-04-30 17:47     ` Peter Maydell
  2026-05-14 18:48   ` Michael Tokarev
  2 siblings, 1 reply; 10+ messages in thread
From: Cédric Le Goater @ 2026-04-30 17:26 UTC (permalink / raw)
  To: Kane Chen, Peter Maydell, Steven Lee, Troy Lee, Jamin Lin,
	Andrew Jeffery, Joel Stanley, open list:ASPEED BMCs,
	open list:All patches CC here
  Cc: Troy Lee, qemu-stable@nongnu.org, Cédric Le Goater

On 4/28/26 07:52, Kane Chen wrote:
> There is a mismatch between the Aspeed OTP model and the Aspeed SBC
> model in how the guest-provided address is handled.
> aspeed_sbc_otp_prog() passes a word-indexed address directly
> to address_space_write() without converting it to a byte offset,
> whereas aspeed_otp_write() expects a byte offset and applies an
> additional shift (otp_addr << 2). This double-shift confusion means
> that an out-of-range word address can lead to a write beyond the
> allocated storage.
> 
> Fix this by adding bounds checking on the word offset before
> converting to byte offset and passing to address_space_write().
> This matches the existing bounds check in aspeed_sbc_otp_read().
> 
> Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
> Cc: qemu-stable@nongnu.org
> Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller model")
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3436
> Reported-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Cédric Le Goater <clg@redhat.com>
> Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
> ---
>   hw/misc/aspeed_sbc.c  | 14 +++++++++++---
>   hw/nvram/aspeed_otp.c | 13 ++++++-------
>   2 files changed, 17 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
> index 065e822e70..8b74dca13c 100644
> --- a/hw/misc/aspeed_sbc.c
> +++ b/hw/misc/aspeed_sbc.c
> @@ -159,13 +159,21 @@ static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
>       MemTxResult ret;
>       AspeedOTPState *otp = &s->otp;
>       uint32_t value = s->regs[R_CAMP1];
> +    uint32_t otp_offset = otp_addr << 2;
>   
> -    ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
> -                        &value, sizeof(value));
> +    if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "Invalid OTP addr 0x%x\n",
> +                      otp_addr);

This log event could be on one line.

> +        return false;
> +    }
> +
> +    ret = address_space_write(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
> +                              &value, sizeof(value));
>       if (ret != MEMTX_OK) {
>           qemu_log_mask(LOG_GUEST_ERROR,
>                         "Failed to write OTP memory, addr = %x\n",
> -                      otp_addr);
> +                      otp_offset);
>           return false;
>       }
>   
> diff --git a/hw/nvram/aspeed_otp.c b/hw/nvram/aspeed_otp.c
> index a60289000c..1a9d3841b8 100644
> --- a/hw/nvram/aspeed_otp.c
> +++ b/hw/nvram/aspeed_otp.c
> @@ -57,12 +57,12 @@ static bool valid_program_data(uint32_t otp_addr,
>       return has_programmable_bits != 0;
>   }
>   
> -static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
> +static bool program_otpmem_data(void *opaque, hwaddr otp_offset,
>                                uint32_t prog_bit, uint32_t *value)
>   {
>       AspeedOTPState *s = opaque;
> +    uint32_t otp_addr = otp_offset >> 2;

I think 'opt_addr' is a bit confusing. It's a word offset.

valid_program_data() could also use an 'otp_offset' arg and
I would introduce a small inline helper to replace variable
'is_odd'

Thanks,

C.



>       bool is_odd = otp_addr & 1;
> -    uint32_t otp_offset = otp_addr << 2;
>   
>       memcpy(value, s->storage + otp_offset, sizeof(uint32_t));
>   
> @@ -79,26 +79,25 @@ static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
>       return true;
>   }
>   
> -static void aspeed_otp_write(void *opaque, hwaddr otp_addr,
> +static void aspeed_otp_write(void *opaque, hwaddr otp_offset,
>                                   uint64_t val, unsigned size)
>   {
>       AspeedOTPState *s = opaque;
> -    uint32_t otp_offset, value;
> +    uint32_t value;
>   
> -    if (!program_otpmem_data(s, otp_addr, val, &value)) {
> +    if (!program_otpmem_data(s, otp_offset, val, &value)) {
>           qemu_log_mask(LOG_GUEST_ERROR,
>                         "%s: Failed to program data, value = %x, bit = %"PRIx64"\n",
>                         __func__, value, val);
>           return;
>       }
>   
> -    otp_offset = otp_addr << 2;
>       memcpy(s->storage + otp_offset, &value, size);
>   
>       if (s->blk) {
>           if (blk_pwrite(s->blk, otp_offset, size, &value, 0) < 0) {
>               qemu_log_mask(LOG_GUEST_ERROR,
> -                          "%s: Failed to write %x to %x\n",
> +                          "%s: Failed to write %x to %"HWADDR_PRIx"\n",
>                             __func__, value, otp_offset);
>   
>               return;



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-04-30 17:26   ` Cédric Le Goater
@ 2026-04-30 17:47     ` Peter Maydell
  2026-04-30 17:54       ` Cédric Le Goater
  0 siblings, 1 reply; 10+ messages in thread
From: Peter Maydell @ 2026-04-30 17:47 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: Kane Chen, Steven Lee, Troy Lee, Jamin Lin, Andrew Jeffery,
	Joel Stanley, open list:ASPEED BMCs,
	open list:All patches CC here, Troy Lee, qemu-stable@nongnu.org,
	Cédric Le Goater

On Thu, 30 Apr 2026 at 18:26, Cédric Le Goater <clg@kaod.org> wrote:
>
> On 4/28/26 07:52, Kane Chen wrote:
> > There is a mismatch between the Aspeed OTP model and the Aspeed SBC
> > model in how the guest-provided address is handled.
> > aspeed_sbc_otp_prog() passes a word-indexed address directly
> > to address_space_write() without converting it to a byte offset,
> > whereas aspeed_otp_write() expects a byte offset and applies an
> > additional shift (otp_addr << 2). This double-shift confusion means
> > that an out-of-range word address can lead to a write beyond the
> > allocated storage.
> >
> > Fix this by adding bounds checking on the word offset before
> > converting to byte offset and passing to address_space_write().
> > This matches the existing bounds check in aspeed_sbc_otp_read().
> >
> > Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
> > Cc: qemu-stable@nongnu.org
> > Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller model")
> > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3436
> > Reported-by: Peter Maydell <peter.maydell@linaro.org>
> > Signed-off-by: Cédric Le Goater <clg@redhat.com>
> > Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
> > ---
> >   hw/misc/aspeed_sbc.c  | 14 +++++++++++---
> >   hw/nvram/aspeed_otp.c | 13 ++++++-------
> >   2 files changed, 17 insertions(+), 10 deletions(-)
> >
> > diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
> > index 065e822e70..8b74dca13c 100644
> > --- a/hw/misc/aspeed_sbc.c
> > +++ b/hw/misc/aspeed_sbc.c
> > @@ -159,13 +159,21 @@ static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
> >       MemTxResult ret;
> >       AspeedOTPState *otp = &s->otp;
> >       uint32_t value = s->regs[R_CAMP1];
> > +    uint32_t otp_offset = otp_addr << 2;
> >
> > -    ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
> > -                        &value, sizeof(value));
> > +    if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "Invalid OTP addr 0x%x\n",
> > +                      otp_addr);
>
> This log event could be on one line.
>
> > +        return false;
> > +    }
> > +
> > +    ret = address_space_write(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
> > +                              &value, sizeof(value));
> >       if (ret != MEMTX_OK) {
> >           qemu_log_mask(LOG_GUEST_ERROR,
> >                         "Failed to write OTP memory, addr = %x\n",
> > -                      otp_addr);
> > +                      otp_offset);
> >           return false;
> >       }
> >
> > diff --git a/hw/nvram/aspeed_otp.c b/hw/nvram/aspeed_otp.c
> > index a60289000c..1a9d3841b8 100644
> > --- a/hw/nvram/aspeed_otp.c
> > +++ b/hw/nvram/aspeed_otp.c
> > @@ -57,12 +57,12 @@ static bool valid_program_data(uint32_t otp_addr,
> >       return has_programmable_bits != 0;
> >   }
> >
> > -static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
> > +static bool program_otpmem_data(void *opaque, hwaddr otp_offset,
> >                                uint32_t prog_bit, uint32_t *value)
> >   {
> >       AspeedOTPState *s = opaque;
> > +    uint32_t otp_addr = otp_offset >> 2;
>
> I think 'opt_addr' is a bit confusing. It's a word offset.

It's the variable name we're currently using for that meaning
everywhere in these two devices, though. It might be better
to keep that cleanup in a separate patch from this one.

-- PMM


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-04-30 17:47     ` Peter Maydell
@ 2026-04-30 17:54       ` Cédric Le Goater
  0 siblings, 0 replies; 10+ messages in thread
From: Cédric Le Goater @ 2026-04-30 17:54 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Kane Chen, Steven Lee, Troy Lee, Jamin Lin, Andrew Jeffery,
	Joel Stanley, open list:ASPEED BMCs,
	open list:All patches CC here, Troy Lee, qemu-stable@nongnu.org,
	Cédric Le Goater

On 4/30/26 19:47, Peter Maydell wrote:
> On Thu, 30 Apr 2026 at 18:26, Cédric Le Goater <clg@kaod.org> wrote:
>>
>> On 4/28/26 07:52, Kane Chen wrote:
>>> There is a mismatch between the Aspeed OTP model and the Aspeed SBC
>>> model in how the guest-provided address is handled.
>>> aspeed_sbc_otp_prog() passes a word-indexed address directly
>>> to address_space_write() without converting it to a byte offset,
>>> whereas aspeed_otp_write() expects a byte offset and applies an
>>> additional shift (otp_addr << 2). This double-shift confusion means
>>> that an out-of-range word address can lead to a write beyond the
>>> allocated storage.
>>>
>>> Fix this by adding bounds checking on the word offset before
>>> converting to byte offset and passing to address_space_write().
>>> This matches the existing bounds check in aspeed_sbc_otp_read().
>>>
>>> Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
>>> Cc: qemu-stable@nongnu.org
>>> Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller model")
>>> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3436
>>> Reported-by: Peter Maydell <peter.maydell@linaro.org>
>>> Signed-off-by: Cédric Le Goater <clg@redhat.com>
>>> Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
>>> ---
>>>    hw/misc/aspeed_sbc.c  | 14 +++++++++++---
>>>    hw/nvram/aspeed_otp.c | 13 ++++++-------
>>>    2 files changed, 17 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
>>> index 065e822e70..8b74dca13c 100644
>>> --- a/hw/misc/aspeed_sbc.c
>>> +++ b/hw/misc/aspeed_sbc.c
>>> @@ -159,13 +159,21 @@ static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
>>>        MemTxResult ret;
>>>        AspeedOTPState *otp = &s->otp;
>>>        uint32_t value = s->regs[R_CAMP1];
>>> +    uint32_t otp_offset = otp_addr << 2;
>>>
>>> -    ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
>>> -                        &value, sizeof(value));
>>> +    if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
>>> +        qemu_log_mask(LOG_GUEST_ERROR,
>>> +                      "Invalid OTP addr 0x%x\n",
>>> +                      otp_addr);
>>
>> This log event could be on one line.
>>
>>> +        return false;
>>> +    }
>>> +
>>> +    ret = address_space_write(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
>>> +                              &value, sizeof(value));
>>>        if (ret != MEMTX_OK) {
>>>            qemu_log_mask(LOG_GUEST_ERROR,
>>>                          "Failed to write OTP memory, addr = %x\n",
>>> -                      otp_addr);
>>> +                      otp_offset);
>>>            return false;
>>>        }
>>>
>>> diff --git a/hw/nvram/aspeed_otp.c b/hw/nvram/aspeed_otp.c
>>> index a60289000c..1a9d3841b8 100644
>>> --- a/hw/nvram/aspeed_otp.c
>>> +++ b/hw/nvram/aspeed_otp.c
>>> @@ -57,12 +57,12 @@ static bool valid_program_data(uint32_t otp_addr,
>>>        return has_programmable_bits != 0;
>>>    }
>>>
>>> -static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
>>> +static bool program_otpmem_data(void *opaque, hwaddr otp_offset,
>>>                                 uint32_t prog_bit, uint32_t *value)
>>>    {
>>>        AspeedOTPState *s = opaque;
>>> +    uint32_t otp_addr = otp_offset >> 2;
>>
>> I think 'opt_addr' is a bit confusing. It's a word offset.
> 
> It's the variable name we're currently using for that meaning
> everywhere in these two devices, though. It might be better
> to keep that cleanup in a separate patch from this one.

OK. Let's do that.


C.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-04-30 11:03   ` Peter Maydell
  2026-04-30 13:48     ` 回覆: " Kane Chen
@ 2026-04-30 17:56     ` Cédric Le Goater
  2026-05-04  5:56       ` Kane Chen
  1 sibling, 1 reply; 10+ messages in thread
From: Cédric Le Goater @ 2026-04-30 17:56 UTC (permalink / raw)
  To: Peter Maydell, Kane Chen
  Cc: Steven Lee, Troy Lee, Jamin Lin, Andrew Jeffery, Joel Stanley,
	open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
	qemu-stable@nongnu.org, Cédric Le Goater

On 4/30/26 13:03, Peter Maydell wrote:
> On Tue, 28 Apr 2026 at 06:53, Kane Chen <kane_chen@aspeedtech.com> wrote:
>>
>> There is a mismatch between the Aspeed OTP model and the Aspeed SBC
>> model in how the guest-provided address is handled.
>> aspeed_sbc_otp_prog() passes a word-indexed address directly
>> to address_space_write() without converting it to a byte offset,
>> whereas aspeed_otp_write() expects a byte offset and applies an
>> additional shift (otp_addr << 2). This double-shift confusion means
>> that an out-of-range word address can lead to a write beyond the
>> allocated storage.
>>
>> Fix this by adding bounds checking on the word offset before
>> converting to byte offset and passing to address_space_write().
>> This matches the existing bounds check in aspeed_sbc_otp_read().
>>
>> Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
>> Cc: qemu-stable@nongnu.org
>> Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller model")
>> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3436
>> Reported-by: Peter Maydell <peter.maydell@linaro.org>
>> Signed-off-by: Cédric Le Goater <clg@redhat.com>
>> Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
>> ---
>>   hw/misc/aspeed_sbc.c  | 14 +++++++++++---
>>   hw/nvram/aspeed_otp.c | 13 ++++++-------
>>   2 files changed, 17 insertions(+), 10 deletions(-)
>>
>> diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
>> index 065e822e70..8b74dca13c 100644
>> --- a/hw/misc/aspeed_sbc.c
>> +++ b/hw/misc/aspeed_sbc.c
>> @@ -159,13 +159,21 @@ static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
>>       MemTxResult ret;
>>       AspeedOTPState *otp = &s->otp;
>>       uint32_t value = s->regs[R_CAMP1];
>> +    uint32_t otp_offset = otp_addr << 2;
>>
>> -    ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
>> -                        &value, sizeof(value));
>> +    if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +                      "Invalid OTP addr 0x%x\n",
>> +                      otp_addr);
>> +        return false;
>> +    }
>> +
>> +    ret = address_space_write(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
>> +                              &value, sizeof(value));
>>       if (ret != MEMTX_OK) {
>>           qemu_log_mask(LOG_GUEST_ERROR,
>>                         "Failed to write OTP memory, addr = %x\n",
>> -                      otp_addr);
>> +                      otp_offset);
> 
> I would stick to reporting otp_addr here:
>   - it's the value the guest actually writes
>   - it matches the logging for "invalid OTP addr above"
>   - it matches what aspeed_sbc_otp_read() logs in the equivalent case
> 
> Otherwise
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>



Applied to

     https://github.com/legoater/qemu aspeed-next

with this change.

Peter,

Feel free to pick the change if needed.

Thanks,

C.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-04-30 17:56     ` Cédric Le Goater
@ 2026-05-04  5:56       ` Kane Chen
  0 siblings, 0 replies; 10+ messages in thread
From: Kane Chen @ 2026-05-04  5:56 UTC (permalink / raw)
  To: Cédric Le Goater, Peter Maydell
  Cc: Steven Lee, Troy Lee, Jamin Lin, Andrew Jeffery, Joel Stanley,
	open list:ASPEED BMCs, open list:All patches CC here, Troy Lee,
	qemu-stable@nongnu.org, Cédric Le Goater

> -----Original Message-----
> From: Cédric Le Goater <clg@kaod.org>
> Sent: Friday, May 1, 2026 1:57 AM
> To: Peter Maydell <peter.maydell@linaro.org>; Kane Chen
> <kane_chen@aspeedtech.com>
> Cc: Steven Lee <steven_lee@aspeedtech.com>; Troy Lee
> <leetroy@gmail.com>; Jamin Lin <jamin_lin@aspeedtech.com>; Andrew
> Jeffery <andrew@codeconstruct.com.au>; Joel Stanley <joel@jms.id.au>; open
> list:ASPEED BMCs <qemu-arm@nongnu.org>; open list:All patches CC here
> <qemu-devel@nongnu.org>; Troy Lee <troy_lee@aspeedtech.com>;
> qemu-stable@nongnu.org; Cédric Le Goater <clg@redhat.com>
> Subject: Re: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP
> write operations
> 
> On 4/30/26 13:03, Peter Maydell wrote:
> > On Tue, 28 Apr 2026 at 06:53, Kane Chen <kane_chen@aspeedtech.com>
> wrote:
> >>
> >> There is a mismatch between the Aspeed OTP model and the Aspeed SBC
> >> model in how the guest-provided address is handled.
> >> aspeed_sbc_otp_prog() passes a word-indexed address directly to
> >> address_space_write() without converting it to a byte offset, whereas
> >> aspeed_otp_write() expects a byte offset and applies an additional
> >> shift (otp_addr << 2). This double-shift confusion means that an
> >> out-of-range word address can lead to a write beyond the allocated
> >> storage.
> >>
> >> Fix this by adding bounds checking on the word offset before
> >> converting to byte offset and passing to address_space_write().
> >> This matches the existing bounds check in aspeed_sbc_otp_read().
> >>
> >> Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
> >> Cc: qemu-stable@nongnu.org
> >> Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller
> >> model")
> >> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3436
> >> Reported-by: Peter Maydell <peter.maydell@linaro.org>
> >> Signed-off-by: Cédric Le Goater <clg@redhat.com>
> >> Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
> >> ---
> >>   hw/misc/aspeed_sbc.c  | 14 +++++++++++---
> >>   hw/nvram/aspeed_otp.c | 13 ++++++-------
> >>   2 files changed, 17 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c index
> >> 065e822e70..8b74dca13c 100644
> >> --- a/hw/misc/aspeed_sbc.c
> >> +++ b/hw/misc/aspeed_sbc.c
> >> @@ -159,13 +159,21 @@ static bool
> aspeed_sbc_otp_prog(AspeedSBCState *s,
> >>       MemTxResult ret;
> >>       AspeedOTPState *otp = &s->otp;
> >>       uint32_t value = s->regs[R_CAMP1];
> >> +    uint32_t otp_offset = otp_addr << 2;
> >>
> >> -    ret = address_space_write(&otp->as, otp_addr,
> MEMTXATTRS_UNSPECIFIED,
> >> -                        &value, sizeof(value));
> >> +    if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
> >> +        qemu_log_mask(LOG_GUEST_ERROR,
> >> +                      "Invalid OTP addr 0x%x\n",
> >> +                      otp_addr);
> >> +        return false;
> >> +    }
> >> +
> >> +    ret = address_space_write(&otp->as, otp_offset,
> MEMTXATTRS_UNSPECIFIED,
> >> +                              &value, sizeof(value));
> >>       if (ret != MEMTX_OK) {
> >>           qemu_log_mask(LOG_GUEST_ERROR,
> >>                         "Failed to write OTP memory, addr = %x\n",
> >> -                      otp_addr);
> >> +                      otp_offset);
> >
> > I would stick to reporting otp_addr here:
> >   - it's the value the guest actually writes
> >   - it matches the logging for "invalid OTP addr above"
> >   - it matches what aspeed_sbc_otp_read() logs in the equivalent case
> >
> > Otherwise
> > Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> 
> 
> 
> Applied to
> 
>      https://github.com/legoater/qemu aspeed-next
> 
> with this change.
> 
> Peter,
> 
> Feel free to pick the change if needed.
> 
> Thanks,
> 
> C.

Hi Cédric/Peter,

Thanks for your review and comments.

Currently, the naming of otp_addr and otp_offset is inconsistent, as both are used to represent the user-provided address. For example, when implementing the OTP module, I followed the naming convention used in the write operation (see the link below for reference):
https://github.com/AspeedTech-BMC/zephyr/blob/aspeed-main-v3.7.0/drivers/misc/aspeed/otp_shell.c#L239

However, in the read path, the code uses the term offset instead (see below):
https://github.com/AspeedTech-BMC/zephyr/blob/aspeed-main-v3.7.0/drivers/misc/aspeed/otp_shell.c#L150

To improve consistency, we could align the naming with otp_offset, following the read path convention. However, I'm not certain if this would be more intuitive. Please let me know if you have any further suggestions regarding the otp_addr / otp_offset naming.

Best Regards,
Kane

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 1/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-04-28  5:52 ` [PATCH v1 1/1] " Kane Chen
  2026-04-30 11:03   ` Peter Maydell
  2026-04-30 17:26   ` Cédric Le Goater
@ 2026-05-14 18:48   ` Michael Tokarev
  2 siblings, 0 replies; 10+ messages in thread
From: Michael Tokarev @ 2026-05-14 18:48 UTC (permalink / raw)
  To: Kane Chen, Cédric Le Goater, Peter Maydell, Steven Lee,
	Troy Lee, Jamin Lin, Andrew Jeffery, Joel Stanley,
	open list:ASPEED BMCs, open list:All patches CC here
  Cc: Troy Lee, qemu-stable@nongnu.org, Cédric Le Goater

On 28.04.2026 08:52, Kane Chen wrote:
> There is a mismatch between the Aspeed OTP model and the Aspeed SBC
> model in how the guest-provided address is handled.
> aspeed_sbc_otp_prog() passes a word-indexed address directly
> to address_space_write() without converting it to a byte offset,
> whereas aspeed_otp_write() expects a byte offset and applies an
> additional shift (otp_addr << 2). This double-shift confusion means
> that an out-of-range word address can lead to a write beyond the
> allocated storage.
> 
> Fix this by adding bounds checking on the word offset before
> converting to byte offset and passing to address_space_write().
> This matches the existing bounds check in aspeed_sbc_otp_read().
> 
> Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
> Cc: qemu-stable@nongnu.org
> Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller model")


FWIW (this change has already landed in the master branch, so it's cast
in stone), I can't find this commit in my git clone of qemu repository.
Neither hash ID nor the name.

Is it this one maybe? https://marc.info/?l=qemu-arm&m=164500409921734,
which is commit e1acf581c9 in qemu?  It has a different commit message
though.

And this patch does not apply to 10.0.x, - in there, there's no
hw/nvram/aspeed_otp.c (688a3dae78 hw/nvram/aspeed_otp: Add ASPEED OTP
memory device model).  I assume it's not needed for 10.0.x, but in
that case, the Fixes: tag isn't even commit e1acf581c9.

Thanks,

/mjt


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-05-14 18:49 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-28  5:52 [PATCH v1 0/1] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations Kane Chen
2026-04-28  5:52 ` [PATCH v1 1/1] " Kane Chen
2026-04-30 11:03   ` Peter Maydell
2026-04-30 13:48     ` 回覆: " Kane Chen
2026-04-30 17:56     ` Cédric Le Goater
2026-05-04  5:56       ` Kane Chen
2026-04-30 17:26   ` Cédric Le Goater
2026-04-30 17:47     ` Peter Maydell
2026-04-30 17:54       ` Cédric Le Goater
2026-05-14 18:48   ` Michael Tokarev

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.