On Wed, Jun 23, 2021 at 01:50:10PM +0800, Jia He wrote: > From: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx> > > Before each invocation of vsnprintf(), do_test() memsets the entire > allocated buffer to a sentinel value. That buffer includes leading and > trailing padding which is never included in the buffer area handed to > vsnprintf (spaces merely for clarity): > > pad test_buffer pad > **** **************** **** > > Then vsnprintf() is invoked with a bufsize argument <= > BUF_SIZE. Suppose bufsize=10, then we'd have e.g. > > |pad | test_buffer |pad | > **** pizza0 **** ****** **** > A B C D E > > where vsnprintf() was given the area from B to D. > > It is obviously a bug for vsnprintf to touch anything between A and B > or between D and E. The former is checked for as one would expect. But > for the latter, we are actually a little stricter in that we check the > area between C and E. > > Split that check in two, providing a clearer error message in case it > was a genuine buffer overrun and not merely a write within the > provided buffer, but after the end of the generated string. > > So far, no part of the vsnprintf() implementation has had any use for > using the whole buffer as scratch space, but it's not unreasonable to > allow that, as long as the result is properly nul-terminated and the > return value is the right one. However, it is somewhat unusual, and > most %<something> won't need this, so keep the [C,D] check, but make > it easy for a later patch to make that part opt-out for certain tests. Reviewed-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> > Signed-off-by: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx> > Tested-by: Jia He <justin.he@xxxxxxx> > Signed-off-by: Jia He <justin.he@xxxxxxx> > Reviewed-by: Petr Mladek <pmladek@xxxxxxxx> > --- > lib/test_printf.c | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/lib/test_printf.c b/lib/test_printf.c > index ec0d5976bb69..d1d2f898ebae 100644 > --- a/lib/test_printf.c > +++ b/lib/test_printf.c > @@ -78,12 +78,17 @@ do_test(int bufsize, const char *expect, int elen, > return 1; > } > > - if (memchr_inv(test_buffer + written + 1, FILL_CHAR, BUF_SIZE + PAD_SIZE - (written + 1))) { > + if (memchr_inv(test_buffer + written + 1, FILL_CHAR, bufsize - (written + 1))) { > pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond the nul-terminator\n", > bufsize, fmt); > return 1; > } > > + if (memchr_inv(test_buffer + bufsize, FILL_CHAR, BUF_SIZE + PAD_SIZE - bufsize)) { > + pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond buffer\n", bufsize, fmt); > + return 1; > + } > + > if (memcmp(test_buffer, expect, written)) { > pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n", > bufsize, fmt, test_buffer, written, expect); > -- > 2.17.1 > -- With Best Regards, Andy Shevchenko