[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] hw/riscv/virt.c: Assemble plic_hart_config string with g_str
From: |
Peter Maydell |
Subject: |
Re: [PATCH] hw/riscv/virt.c: Assemble plic_hart_config string with g_strjoinv() |
Date: |
Thu, 12 Aug 2021 17:28:09 +0100 |
On Thu, 12 Aug 2021 at 17:09, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> Hi Peter,
>
> On 8/12/21 4:46 PM, Peter Maydell wrote:
> > In the riscv virt machine init function, We assemble a string
> > plic_hart_config which is a comma-separated list of N copies of the
> > VIRT_PLIC_HART_CONFIG string. The code that does this has a
> > misunderstanding of the strncat() length argument. If the source
> > string is too large strncat() will write a maximum of length+1 bytes
> > (length bytes from the source string plus a trailing NUL), but the
> > code here assumes that it will write only length bytes at most.
> >
> > This isn't an actual bug because the code has correctly precalculated
> > the amount of memory it needs to allocate so that it will never be
> > too small (i.e. we could have used plain old strcat()), but it does
> > mean that the code looks like it has a guard against accidental
> > overrun when it doesn't.
> >
> > Rewrite the string handling here to use the glib g_strjoinv()
> > function, which means we don't need to do careful accountancy of
> > string lengths, and makes it clearer that what we're doing is
> > "create a comma-separated string".
> >
> > Fixes: Coverity 1460752
> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> > ---
> > hw/riscv/virt.c | 33 ++++++++++++++++++++-------------
> > 1 file changed, 20 insertions(+), 13 deletions(-)
> >
> > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > index 4a3cd2599a5..26bc8d289ba 100644
> > --- a/hw/riscv/virt.c
> > +++ b/hw/riscv/virt.c
> > @@ -541,6 +541,24 @@ static FWCfgState *create_fw_cfg(const MachineState
> > *mc)
> > return fw_cfg;
> > }
> >
> > +/*
> > + * Return the per-socket PLIC hart topology configuration string
> > + * (caller must free with g_free())
> > + */
> > +static char *plic_hart_config_string(int hart_count)
> > +{
> > + g_autofree const char **vals = g_new(const char *, hart_count + 1);
> > + int i;
> > +
> > + for (i = 0; i < hart_count; i++) {
> > + vals[i] = VIRT_PLIC_HART_CONFIG;
>
> Have you considered adding plic_hart_config_string() an extra
> 'const char *plic_config' argument (declaring it in a new
> include/hw/riscv/plic_hart.h)?
> We could use it in the other boards:
I hadn't noticed those, because Coverity doesn't complain about them.
Both sifive_u.c and microchip_pfsoc.c would need slightly different
code, though, because they are setting up a string like "M,MS,MS,MS"
where the first element is different from the others.
This is (I think) because they have the same misconception about
strncat()'s length argument, but they have a counterbalancing bug
where they reduce the 'remaining bytes in buffer' argument by 2 each
time round the loop even though the length of the first element in
their comma separated string is only 1 byte -- so they are accidentally
turning the length value into what it ought to be.
So those other board files should definitely also be updated to
use g_strjoinv(), but I'm not sure that we can usefully share code.
(We could have a function that takes an argument for the string
for the first CPU and one for the other CPUs, which would work
for all the boards we have now, but that feels a bit contrived
and maybe some other boards in future would want to make different
entries in the list be different...)
-- PMM