From: Petr Mladek <pmladek@suse.com>
To: "Thomas Weißschuh" <thomas.weissschuh@linutronix.de>
Cc: Dan Carpenter <dan.carpenter@linaro.org>,
John Ogness <john.ogness@linutronix.de>,
Kees Cook <kees@kernel.org>,
linux-hardening@vger.kernel.org
Subject: Re: [bug report] printk: ringbuffer: Add KUnit test
Date: Tue, 1 Jul 2025 17:56:19 +0200 [thread overview]
Message-ID: <aGQFIzXtyHw8FAeq@pathway.suse.cz> (raw)
In-Reply-To: <20250626082605-c5fbbb88-f6cc-4659-bea0-a283cdb58e81@linutronix.de>
On Thu 2025-06-26 08:59:52, Thomas Weißschuh wrote:
> On Wed, Jun 25, 2025 at 10:22:19AM -0500, Dan Carpenter wrote:
> > Hello Thomas Weißschuh,
> >
> > The patch 5ea2bcdfbf46: "printk: ringbuffer: Add KUnit test" from Jun
> > 12, 2025, leads to the following static checker warning:
> >
> > kernel/printk/printk_ringbuffer_kunit_test.c:91 prbtest_check_data()
> > (unpublished script worries this an off by one)
> >
> > kernel/printk/printk_ringbuffer_kunit_test.c
> > 83 static bool prbtest_check_data(const struct prbtest_rbdata *dat)
> > 84 {
> > 85 unsigned int len;
> > 86
> > 87 /* Sane length? */
> > 88 if (dat->len < 1 || dat->len > MAX_RBDATA_TEXT_SIZE)
> > 89 return false;
> > 90
> > --> 91 if (dat->text[dat->len] != '\0')
> > 92 return false;
> > 93
> >
> > My question is that the prbtest_rbdata structure is declared like this:
> >
> > 53 /* test data structure */
> > 54 struct prbtest_rbdata {
> > 55 unsigned int len;
> > 56 char text[] __counted_by(len);
> > 57 };
> >
> > The size of text is not really counted by len, it's "MAX_RBDATA_TEXT_SIZE
> > + 1". The condition "if (dat->text[dat->len] != '\0')" is reading one
> > element beyond the __counted_by() value so something should complain if
> > we enable all the debugging, right?
>
> You are right, we are reading past the __counted_by().
> But I don't get any complains with CONFIG_FORTIFY_SOURCE=y and CONFIG_KASAN=y
> on either clang or gcc.
> We could remove the __counted_by, but I assume somebody will try to add it back
> at some point.
> Or we account for the terminator in dat->len:
It means that the value will be the size occupied by the string
including the trailing '\0'.
It means that we need to rename it, for example, len -> size.
Because using "len" for size is confusing and error prone.
See below.
> diff --git a/kernel/printk/printk_ringbuffer_kunit_test.c b/kernel/printk/printk_ringbuffer_kunit_test.c
> index ef4a2beea57a..106f4c7ffc86 100644
> --- a/kernel/printk/printk_ringbuffer_kunit_test.c
> +++ b/kernel/printk/printk_ringbuffer_kunit_test.c
> @@ -85,14 +85,15 @@ static bool prbtest_check_data(const struct prbtest_rbdata *dat)
> unsigned int len;
>
> /* Sane length? */
> - if (dat->len < 1 || dat->len > MAX_RBDATA_TEXT_SIZE)
> + if (dat->len < 2 || dat->len > MAX_RBDATA_TEXT_SIZE + 1)
> return false;
>
> - if (dat->text[dat->len] != '\0')
> + len = dat->len - 1;
This is one example, where it just looks just ugly.
> +
> + if (dat->text[len] != '\0')
> return false;
>
> /* String repeats with the same character? */
> - len = dat->len;
> while (len--) {
> if (dat->text[len] != dat->text[0])
> return false;
> @@ -114,10 +115,9 @@ static int prbtest_writer(void *data)
> kunit_info(tr->test_data->test, "start thread %03lu (writer)\n", tr->num);
>
> for (;;) {
> - /* ensure at least 1 character */
> - text_size = get_random_u32_inclusive(1, MAX_RBDATA_TEXT_SIZE);
> - /* +1 for terminator. */
> - record_size = sizeof(struct prbtest_rbdata) + text_size + 1;
> + /* ensure at least 1 character, +1 for terminator */
> + text_size = get_random_u32_inclusive(1, MAX_RBDATA_TEXT_SIZE) + 1;
This is where the naming goes beyond sanity. We allow to break the
limit by setting "text_size" to MAX_RBDATA_TEXT_SIZE + 1.
It is because MAX_RBDATA_TEXT_SIZE is used to limit the length of
the string (without the trailing '\0'). Huh.
> + record_size = sizeof(struct prbtest_rbdata) + text_size;
> WARN_ON_ONCE(record_size > MAX_PRB_RECORD_SIZE);
>
> /* specify the text sizes for reservation */
> @@ -142,7 +142,7 @@ static int prbtest_writer(void *data)
> dat = (struct prbtest_rbdata *)r.text_buf;
> dat->len = text_size;
> memset(dat->text, text_id, text_size);
> - dat->text[text_size] = 0;
> + dat->text[text_size - 1] = '\0';
>
> prb_commit(&e);
This patch forgot to update prbtest_fail_record(). It limits the
printed string by dat->len. But the value newly counts the trailing
'\0'.
OK, I am going to send a patch with sane names where all this
should be fixed.
Best Regards,
Petr
next prev parent reply other threads:[~2025-07-01 15:56 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-25 15:22 [bug report] printk: ringbuffer: Add KUnit test Dan Carpenter
2025-06-26 6:59 ` Thomas Weißschuh
2025-07-01 15:23 ` Dan Carpenter
2025-07-01 15:56 ` Petr Mladek [this message]
2025-07-02 20:22 ` Nathan Chancellor
2025-07-02 20:33 ` Dan Carpenter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aGQFIzXtyHw8FAeq@pathway.suse.cz \
--to=pmladek@suse.com \
--cc=dan.carpenter@linaro.org \
--cc=john.ogness@linutronix.de \
--cc=kees@kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=thomas.weissschuh@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.