mirror of https://lore.kernel.org/linux-amlogic/
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Link Mauve" <linkmauve@linkmauve.fr>
Cc: Frank.Li@kernel.org, neil.armstrong@linaro.org,
	linux-amlogic@lists.infradead.org, imx@lists.linux.dev,
	ojeda@kernel.org
Subject: Re: [PATCH v5 3/3] nvmem: make all reg_write callbacks take const void *
Date: Tue, 04 Aug 2026 15:15:03 +0000	[thread overview]
Message-ID: <20260804151503.CEE6C1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260804135940.2378737-4-linkmauve@linkmauve.fr>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

Pre-existing issues:
- [Critical] Kernel stack out-of-bounds read in `sprd_efuse_read` and logic error in `sprd_efuse_write`.
- [High] Nvmem offset is incorrectly treated as a word index instead of a byte offset.
- [High] Validation of PUF user fuses can be bypassed during multi-word writes.
- [High] The OCOTP controller is permanently left in programming mode if a write or read operation fails.
- [High] OP-TEE session is leaked on invalid arguments in stm32_bsec_optee_ta_write.
--

--- Patch [3]: [PATCH v5 3/3] nvmem: make all reg_write callbacks take const void * ---
commit 09f4e61d9e81ee5be0fd90c9f53ec6d29da8b412
Author: Link Mauve <linkmauve@linkmauve.fr>
Subject: nvmem: make all reg_write callbacks take const void *

This commit updates the nvmem subsystem to use a pointer to immutable data
for all reg_write callbacks. It modifies the various drivers to change the
function signatures accordingly.

> diff --git a/drivers/nvmem/bcm-ocotp.c b/drivers/nvmem/bcm-ocotp.c
> index 2490f44caa409..02adfd787de85 100644
> --- a/drivers/nvmem/bcm-ocotp.c
> +++ b/drivers/nvmem/bcm-ocotp.c
[ ... ]
> @@ -179,11 +179,11 @@ static int bcm_otpc_read(void *context, unsigned int offset, void *val,
>  	return 0;
>  }
>  
> -static int bcm_otpc_write(void *context, unsigned int offset, void *val,
> -	size_t bytes)
> +static int bcm_otpc_write(void *context, unsigned int offset, const void *val,
> +			  size_t bytes)
>  {
>  	struct otpc_priv *priv = context;
> -	u32 *buf = val;
> +	const u32 *buf = val;
>  	u32 bytes_written;

[Severity: High]
This is a pre-existing issue, but if a read or write operation fails in
bcm_otpc_read() or bcm_otpc_write(), does the controller get stuck in
programming mode?

Looking at bcm_otpc_write(), if poll_cpu_status() fails, it returns early:

        ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE);
        reset_start_bit(priv->base);
        if (ret) {
                dev_err(priv->dev, "otp write error: 0x%x", ret);
                return -EIO;
        }

This bypasses the disable_ocotp_program() cleanup. A similar early return
in bcm_otpc_read() bypasses reset_start_bit().

Could this leave the hardware with start bits set or in programming mode?

> diff --git a/drivers/nvmem/imx-ocotp-scu.c b/drivers/nvmem/imx-ocotp-scu.c
> index 517d83e11af2c..57008228100f5 100644
> --- a/drivers/nvmem/imx-ocotp-scu.c
> +++ b/drivers/nvmem/imx-ocotp-scu.c
[ ... ]
> @@ -178,11 +178,11 @@ static int imx_scu_ocotp_read(void *context, unsigned int offset,
>  }
>  
>  static int imx_scu_ocotp_write(void *context, unsigned int offset,
> -			       void *val, size_t bytes)
> +			       const void *val, size_t bytes)
>  {
>  	struct ocotp_priv *priv = context;
>  	struct arm_smccc_res res;
> -	u32 *buf = val;
> +	const u32 *buf = val;
>  	u32 tmp;
>  	u32 index;

[Severity: High]
This is a pre-existing issue, but does this code treat the byte offset as a
word index?

In both imx_scu_ocotp_read() and imx_scu_ocotp_write(), the byte offset is
assigned directly to index without dividing by 4:

        index = offset;

If a client requests a byte offset like 4, wouldn't this result in
accessing word 4 (which is byte offset 16), potentially reading or writing
incorrect fuses?

> diff --git a/drivers/nvmem/sprd-efuse.c b/drivers/nvmem/sprd-efuse.c
> index 1a7e4e5d8b86c..f960fa8cb25cf 100644
> --- a/drivers/nvmem/sprd-efuse.c
> +++ b/drivers/nvmem/sprd-efuse.c
[ ... ]
> @@ -321,7 +321,7 @@ static int sprd_efuse_read(void *context, u32 offset, void *val, size_t bytes)
>  	return ret;
>  }
>  
> -static int sprd_efuse_write(void *context, u32 offset, void *val, size_t bytes)
> +static int sprd_efuse_write(void *context, u32 offset, const void *val, size_t bytes)
>  {
>  	struct sprd_efuse *efuse = context;
>  	bool blk_double = efuse->data->blk_double;

[Severity: Critical]
This is a pre-existing issue, but can this lead to an out-of-bounds kernel
stack read in sprd_efuse_read() and logic errors in sprd_efuse_write()?

In sprd_efuse_read(), there is a 4-byte local variable:

        u32 data;

If a caller requests a multi-byte read where bytes > 4, the memcpy uses the
requested size:

        memcpy(val, &data, bytes);

Does this copy out-of-bounds kernel stack memory into the output buffer?

Similarly, in sprd_efuse_write(), it passes the raw byte offset as a block
index and writes without looping over the requested bytes:

        ret = sprd_efuse_raw_prog(efuse, offset, blk_double, lock, val);

Would this write to the wrong hardware block and fail to process sizes
larger than a single word?

> diff --git a/drivers/nvmem/stm32-bsec-optee-ta.c b/drivers/nvmem/stm32-bsec-optee-ta.c
> index f89ce791dd12a..3184b976b1f91 100644
> --- a/drivers/nvmem/stm32-bsec-optee-ta.c
> +++ b/drivers/nvmem/stm32-bsec-optee-ta.c
[ ... ]
> @@ -203,7 +203,7 @@ int stm32_bsec_optee_ta_read(struct tee_context *ctx, unsigned int offset,
>  
>  /* stm32_bsec_optee_ta_write() - nvmem write access using PTA client driver */
>  int stm32_bsec_optee_ta_write(struct tee_context *ctx, unsigned int lower,
> -			      unsigned int offset, void *buf, size_t bytes)
> +			      unsigned int offset, const void *buf, size_t bytes)
>  {	struct tee_shm *shm;
>  	struct tee_ioctl_invoke_arg arg;
>  	struct tee_param param[2];

[Severity: High]
This is a pre-existing issue, but could this leak an OP-TEE session on
invalid arguments?

In stm32_bsec_optee_ta_write(), the session is opened, but if the
alignment check fails, it returns early:

        ret = stm32_bsec_ta_open_session(ctx, &session_id);
        if (ret)
                return ret;

        /* Allow only writing complete 32-bits aligned words */
        if ((bytes % 4) || (offset % 4))
                return -EINVAL;

Does returning -EINVAL bypass stm32_bsec_ta_close_session() and exhaust
OP-TEE sessions?

> diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c
> index d297ff150dc02..54905a608157d 100644
> --- a/drivers/nvmem/zynqmp_nvmem.c
> +++ b/drivers/nvmem/zynqmp_nvmem.c
[ ... ]
> @@ -183,7 +183,7 @@ static int zynqmp_nvmem_read(void *context, unsigned int offset, void *val, size
>  }
>  
>  static int zynqmp_nvmem_write(void *context,
> -			      unsigned int offset, void *val, size_t bytes)
> +			      unsigned int offset, const void *val, size_t bytes)
>  {
>  	int pufflag = 0;
>  
> @@ -194,7 +194,7 @@ static int zynqmp_nvmem_write(void *context,
>  		pufflag = 1;
>  
>  	return zynqmp_efuse_access(context, offset,
> -				   val, bytes, EFUSE_WRITE, pufflag);
> +				   (void *)val, bytes, EFUSE_WRITE, pufflag);
>  }

[Severity: High]
This isn't a bug introduced by this patch, but can the PUF user fuse
validation be bypassed during a multi-word write?

In zynqmp_efuse_access(), the validation logic checks the first word and
relies on an exact match of the starting offset:

        if (pufflag == 1 && flag == EFUSE_WRITE) {
                memcpy(&value, val, sizeof(value));
                if ((offset == EFUSE_PUF_START_OFFSET ||
                     offset == EFUSE_PUF_MID_OFFSET) &&
                     ...)

If a multi-word write starts before the restricted offsets, it bypasses the
exact-match offset checks. In this scenario, pufflag evaluates to 0, which
completely disables the PUF-specific validation logic for the overlapping
words.

Could this allow forbidden bits in the PUF fuses to be programmed?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260804135940.2378737-1-linkmauve@linkmauve.fr?part=3

_______________________________________________
linux-amlogic mailing list
linux-amlogic@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-amlogic

      reply	other threads:[~2026-08-04 15:15 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-04 13:59 [PATCH v5 0/3] nvmem: migrate to const void * in reg_write Link Mauve
2026-08-04 13:59 ` [PATCH v5 1/3] firmware: meson: pass a const buffer to meson_sm_call_write() Link Mauve
2026-08-04 13:59 ` [PATCH v5 2/3] nvmem: core: deprecate reg_write callback with reg_write_const Link Mauve
2026-08-04 13:59 ` [PATCH v5 3/3] nvmem: make all reg_write callbacks take const void * Link Mauve
2026-08-04 15:15   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260804151503.CEE6C1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=imx@lists.linux.dev \
    --cc=linkmauve@linkmauve.fr \
    --cc=linux-amlogic@lists.infradead.org \
    --cc=neil.armstrong@linaro.org \
    --cc=ojeda@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome