On Thu, 12 Aug 2021 at 17:09, Philippe Mathieu-Daudé <f4...@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.mayd...@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