Hello Michal,

> -----Original Message-----
> From: Michal Simek <[email protected]>
> Sent: Thursday 10 September 2026 9:59
> 
> On 9/10/26 09:56, Maarten Brock wrote:
> > Hello Sriram and Drew,
> >
> > It seems to me that the limit of 50 for MAX_NAME_LENGTH is pretty arbitrary.
> > If you expect it to easily overflow, why not make that larger as well?
> 
> do you have a case where your board, carrier cards will require more then 50
> chars? This has been designed for Kria SOM where you have name in board eeprom
> and carrier card eeprom and it is never over 50 chars.

No, I do not. I was just following the logic in the patch comments.

> -----Original Message-----
> From: Michal Simek <[email protected]>
> Sent: Thursday 10 September 2026 10:04
> 
> On 9/9/26 21:20, Sriram Sriram wrote:
> > From: Drew Kluemke <[email protected]>
> >
> > board_name_decode() assembles the board name into a calloc'd buffer of
> > MAX_NAME_LENGTH (50) bytes using strcat(). It appends CONFIG_SYS_BOARD
> > and then, for every detected EEPROM descriptor, "-", desc->name (up to
> > 16 characters), "-rev" and desc->revision (up to 8 characters).
> >
> > The length check runs only after the loop, so it cannot prevent the
> > overflow it documents. Each descriptor contributes up to 29 characters,
> > so a base board plus a carrier card already exceeds the buffer, and the
> > data being concatenated comes from the EEPROM.

To me this indicates it is very easy to overflow the buffer.

I have not followed where the result of board_name_decode() goes
and whether 50 is a logical bound there. But since it is locally defined
without any comments it seems an arbitrary choice.

And if both these assumptions are true (expect overflow and arbitrary bound)
then it is probably a good idea to use a larger bound.

> > Use strlcat() bounded to MAX_NAME_LENGTH so the writes are truncated
> > rather than overflowing the allocation. Truncation leaves a string of
> > MAX_NAME_LENGTH - 1 characters, so relax the check accordingly;
> > as written it could never fire once strlcat() is used.
> >
> > Signed-off-by: Drew Kluemke <[email protected]>
> > Signed-off-by: Sriram Sriram <[email protected]>
> > ---
> >   board/xilinx/common/board.c | 20 ++++++++++++--------
> >   1 file changed, 12 insertions(+), 8 deletions(-)
> >
> > diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c
> > index f45b879736e..690991bb435 100644
> > --- a/board/xilinx/common/board.c
> > +++ b/board/xilinx/common/board.c
> > @@ -590,38 +590,42 @@ char * __maybe_unused __weak board_name_decode(void)
> >
> >             /* The first string should be soc name */
> >             if (!id)
> > -                   strcat(board_local_name, CONFIG_SYS_BOARD);
> > +                   strlcat(board_local_name, CONFIG_SYS_BOARD,
> > +                           MAX_NAME_LENGTH);
> 
> I actually got a path (c&p below) for the same issue some days ago internally
> and also reviewed it already. But unfortunately it wasn't sent out yet.
> The difference is that it is checking len at the end of every loop to get out 
> of
> it earlier.
> 
> Thanks,
> Michal
> 
> 
> 
>   Author:     Pranav Tilak <[email protected]>
>   AuthorDate: Wed Sep 9 10:13:09 2026 +0530
> 
>       board: xilinx: Fix heap buffer overflow in board_name_decode()
> 
>       board_name_decode() builds the board name by repeatedly appending
>       to a fixed MAX_NAME_LENGTH (50-byte) buffer with strcat(), and only
>       checks for overflow once, after the entire loop over all detected
>       nvmemX EEPROM devices has completed. If enough devices are present
>       and their name/revision fields are long enough, strcat() can write
>       past the end of the buffer before the overflow check is reached,
>       resulting in heap memory corruption.
> 
>       Fix this by using strlcat() instead, which bounds every write to
>       the destination buffer size and prevents overrunning the allocation.
>       Use its return value to detect truncation during board name
>       construction instead of relying on a single length check after all
>       EEPROM devices have been processed.
> 
>       Fixes: 52ff1626cf4c ("xilinx: common: Enabling generic function for DT
> reselection")
>       Signed-off-by: Pranav Tilak <[email protected]>
> 
>   diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c
>   index bdccf0732d2a..964817d98e65 100644
>   --- a/board/xilinx/common/board.c
>   +++ b/board/xilinx/common/board.c
>   @@ -571,8 +571,9 @@ int __maybe_unused board_fit_config_name_match(const 
> char
> *name)
> 
>    char * __maybe_unused __weak board_name_decode(void)
>    {
>   -   char *board_local_name;
>       struct xilinx_board_description *desc;
>   +   char *board_local_name;
>   +   size_t len = 0;
>       int i, id;
> 
>       board_local_name = calloc(1, MAX_NAME_LENGTH);
>   @@ -592,39 +593,36 @@ char * __maybe_unused __weak board_name_decode(void)
> 
>               /* The first string should be soc name */
>               if (!id)
>   -                   strcat(board_local_name, CONFIG_SYS_BOARD);
>   +                   len = strlcat(board_local_name, CONFIG_SYS_BOARD, 
> MAX_NAME_LENGTH);
> 
>               /*
>                * For two purpose here:
>                * soc_name- eg: zynqmp-
>                * and between base board and CC eg: ..revA-sck...
>                */
>   -           strcat(board_local_name, "-");
>   +           len = strlcat(board_local_name, "-", MAX_NAME_LENGTH);
> 
>               if (desc->name[0]) {
>                       /* For DT composition name needs to be lowercase */
>                       for (i = 0; i < sizeof(desc->name); i++)
>                               desc->name[i] = tolower(desc->name[i]);
> 
>   -                   strcat(board_local_name, desc->name);
>   +                   len = strlcat(board_local_name, desc->name, 
> MAX_NAME_LENGTH);
>               }
>               if (desc->revision[0]) {
>   -                   strcat(board_local_name, "-rev");
>   +                   len = strlcat(board_local_name, "-rev", 
> MAX_NAME_LENGTH);
> 
>                       /* And revision needs to be uppercase */
>                       for (i = 0; i < sizeof(desc->revision); i++)
>                               desc->revision[i] = toupper(desc->revision[i]);
> 
>   -                   strcat(board_local_name, desc->revision);
>   +                   len = strlcat(board_local_name, desc->revision, 
> MAX_NAME_LENGTH);
>               }
>   -   }
> 
>   -   /*
>   -    * Longer strings will end up with buffer overflow and potential
>   -    * attacks that's why check it
>   -    */
>   -   if (strlen(board_local_name) >= MAX_NAME_LENGTH)
>   -           panic("Board name can't be determined\n");
>   +           /* Reject truncated board names. */
>   +           if (len >= MAX_NAME_LENGTH)
>   +                   panic("Board name can't be determined\n");
>   +   }
> 
>       if (strlen(board_local_name))
>               return board_local_name;
> 

I would prefer the patch from Pranav Tilak which doesn't need an extra strlen() 
call.

Kind Regards,
Maarten

Reply via email to