nvmem: core: Fix possible buffer overflow on nvmem cell write

Message ID 20231003131343.1324962-1-loic.poulain@linaro.org
State New
Headers
Series nvmem: core: Fix possible buffer overflow on nvmem cell write |

Commit Message

Loic Poulain Oct. 3, 2023, 1:13 p.m. UTC
  Nothing prevents a nvmem consumer to try writing excessive data to a
given nvmem cell (except when bit_offset is 0). The allocated buffer
of size 'cell->bytes' in nvmem_cell_prepare_write_buffer may not be
large enough to host the copied 'len' bytes.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
---
 drivers/nvmem/core.c | 3 +++
 1 file changed, 3 insertions(+)
  

Comments

Srinivas Kandagatla Oct. 7, 2023, 10:22 a.m. UTC | #1
Thanks Loic for the patch,

On 03/10/2023 14:13, Loic Poulain wrote:
> Nothing prevents a nvmem consumer to try writing excessive data to a
> given nvmem cell (except when bit_offset is 0). The allocated buffer
> of size 'cell->bytes' in nvmem_cell_prepare_write_buffer may not be
> large enough to host the copied 'len' bytes.
> 
Did you hit this path?

  __nvmem_cell_entry_write already has a check for (cell->bit_offset == 
0 && len != cell->bytes))

What is the bit_offset in your case?

Can you provide more details?

thanks,
srini

> Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
> ---
>   drivers/nvmem/core.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> index eaf6a3fe8ca6..0b27ab3b3b86 100644
> --- a/drivers/nvmem/core.c
> +++ b/drivers/nvmem/core.c
> @@ -1654,6 +1654,9 @@ static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell_entry *cell,
>   	int i, rc, nbits, bit_offset = cell->bit_offset;
>   	u8 v, *p, *buf, *b, pbyte, pbits;
>   
> +	if (len > cell->bytes)
> +		return ERR_PTR(-EINVAL);
> +
>   	nbits = cell->nbits;
>   	buf = kzalloc(cell->bytes, GFP_KERNEL);
>   	if (!buf)
  
Loic Poulain Oct. 16, 2023, 1:48 p.m. UTC | #2
Hi Srini,

On Sat, 7 Oct 2023 at 12:22, Srinivas Kandagatla
<srinivas.kandagatla@linaro.org> wrote:
>
> Thanks Loic for the patch,
>
> On 03/10/2023 14:13, Loic Poulain wrote:
> > Nothing prevents a nvmem consumer to try writing excessive data to a
> > given nvmem cell (except when bit_offset is 0). The allocated buffer
> > of size 'cell->bytes' in nvmem_cell_prepare_write_buffer may not be
> > large enough to host the copied 'len' bytes.
> >
> Did you hit this path?
>
>   __nvmem_cell_entry_write already has a check for (cell->bit_offset ==
> 0 && len != cell->bytes))
>
> What is the bit_offset in your case?
>
> Can you provide more details?

I hit the issue while playing with nvmem-reboot-mode driver,
allocating 2-bit of a persistent register at bit-offset 2 for the
reboot mode. nvmem-reboot-mode drivers call nvmem_cell_write() with a
32-bit len value, so we end in nvmem_cell_prepare_write_buffer
allocating a 1-byte (cell->bytes) buffer and copying a 4-byte len
value into it. You can find below the dts example.

```
{
     &snvs_lpgpr{
         #address-cells = <1>;
         #size-cells = <1>;

        something@0 {
             /* reg[2:0] */
             reg = <0x0 0x4>;
             bits = <2 2>;
        };

        reboot_mode: reboot-mode@0 {
            /* reg[4:2] */
            reg = <0x0 0x4>;
            bits = <2 2>;
        };
    };

    reboot-mode {
        compatible = "nvmem-reboot-mode";
        nvmem-cells = <&reboot_mode>;
        nvmem-cell-names = "reboot-mode";
        mode-normal = <0>;
        mode-fastboot = <1>;
        mode-recovery = <2>;
    };
};
```
  

Patch

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index eaf6a3fe8ca6..0b27ab3b3b86 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1654,6 +1654,9 @@  static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell_entry *cell,
 	int i, rc, nbits, bit_offset = cell->bit_offset;
 	u8 v, *p, *buf, *b, pbyte, pbits;
 
+	if (len > cell->bytes)
+		return ERR_PTR(-EINVAL);
+
 	nbits = cell->nbits;
 	buf = kzalloc(cell->bytes, GFP_KERNEL);
 	if (!buf)