From: Kees Cook <keescook@chromium.org>
To: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>,
Nathan Chancellor <nathan@kernel.org>,
rui.zhang@intel.com, lukasz.luba@arm.com, gustavoars@kernel.org,
morbo@google.com, justinstitt@google.com,
stanislaw.gruszka@linux.intel.com, linux-pm@vger.kernel.org,
linux-hardening@vger.kernel.org, llvm@lists.linux.dev,
patches@lists.linux.dev
Subject: Re: [PATCH] thermal: core: Move initial num_trips assignment before memcpy()
Date: Tue, 27 Feb 2024 08:26:06 -0800 [thread overview]
Message-ID: <202402270816.0EA3349A76@keescook> (raw)
In-Reply-To: <f81af0ae-7458-47d3-90ae-71d5217ee7dd@linaro.org>
On Tue, Feb 27, 2024 at 04:37:36PM +0100, Daniel Lezcano wrote:
> On 27/02/2024 12:09, Rafael J. Wysocki wrote:
> > On Tue, Feb 27, 2024 at 11:14 AM Daniel Lezcano
> > <daniel.lezcano@linaro.org> wrote:
> > >
> > > On 27/02/2024 01:54, Nathan Chancellor wrote:
> > > > When booting a CONFIG_FORTIFY_SOURCE=y kernel compiled with a toolchain
> > > > that supports __counted_by() (such as clang-18 and newer), there is a
> > > > panic on boot:
> > > >
> > > > [ 2.913770] memcpy: detected buffer overflow: 72 byte write of buffer size 0
> > > > [ 2.920834] WARNING: CPU: 2 PID: 1 at lib/string_helpers.c:1027 __fortify_report+0x5c/0x74
> > > > ...
> > > > [ 3.039208] Call trace:
> > > > [ 3.041643] __fortify_report+0x5c/0x74
> > > > [ 3.045469] __fortify_panic+0x18/0x20
> > > > [ 3.049209] thermal_zone_device_register_with_trips+0x4c8/0x4f8
> > > >
> > > > This panic occurs because trips is counted by num_trips but num_trips is
> > > > assigned after the call to memcpy(), so the fortify checks think the
> > > > buffer size is zero because tz was allocated with kzalloc().
> > > >
> > > > Move the num_trips assignment before the memcpy() to resolve the panic
> > > > and ensure that the fortify checks work properly.
> > > >
> > > > Fixes: 9b0a62758665 ("thermal: core: Store zone trips table in struct thermal_zone_device")
> > > > Signed-off-by: Nathan Chancellor <nathan@kernel.org>
> > > > ---
> > > > drivers/thermal/thermal_core.c | 2 +-
> > > > 1 file changed, 1 insertion(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> > > > index bb21f78b4bfa..1eabc8ebe27d 100644
> > > > --- a/drivers/thermal/thermal_core.c
> > > > +++ b/drivers/thermal/thermal_core.c
> > > > @@ -1354,8 +1354,8 @@ thermal_zone_device_register_with_trips(const char *type,
> > > >
> > > > tz->device.class = thermal_class;
> > > > tz->devdata = devdata;
> > > > - memcpy(tz->trips, trips, num_trips * sizeof(*trips));
> > > > tz->num_trips = num_trips;
> > > > + memcpy(tz->trips, trips, num_trips * sizeof(*trips));
> > >
> > > IIUC, clang-18 is used and supports __counted_by().
> > >
> > > Is it possible sizeof(*trips) returns already the real trips array size
> > > and we are multiplying it again by num_trips ?
> > >
> > > While with an older compiler, __counted_by() does nothing and we have to
> > > multiply by num_trips ?
> > >
> > > IOW, the array size arithmetic is different depending if we have
> > > _counted_by supported or not ?
> >
> > IIUC it is just the instrumentation using the current value of
> > tz->num_trips (which is 0 before the initialization).
>
> Right, but I am wondering if
>
> memcpy(tz->trips, trips, num_trips * sizeof(*trips));
>
> is still correct with __counted_by because:
>
> (1) if the compiler supports it:
>
> sizeof(*trips) == 24 bytes * num_trips
I think you're misunderstanding. The above sizeof() only evaluates a
single instance -- it has no idea how many more there may be.
Specifically:
sizeof(*trips) == sizeof(struct thermal_trip)
> then:
>
> memcpy(tz->trips, trips, num_trips * sizeof(*trips));
>
> memcpy(tz->trips, trips, num_trips * 24 * num_trips);
>
> ==> memory size = 24 * num_trips^2
It's not counted twice. Under CONFIG_FORTIFY_SOURCE=y, memcpy is a macro
that expands to a checking routine (see include/linux/fortify-string.h),
which is using __builtin_dynamic_object_size() to determine the
available size of the destination buffer (tz->trips). Specifically:
__builtin_dynamic_object_size(tz->trips)
When __bdos evaluates a flexible array (i.e. tz->trips), it will see the
associated 'counted_by' attribute, and go look up the value of the
designated struct member (tz->num_trips). It then calculates:
sizeof(*tz->trips) /* a single instance */
*
tz->num_trips
Before the patch, tz->num_trips is 0, so the destination buffer size
appears to be of size 0 bytes. After the patch, it contains the
same value as the "num_trips" function argument, so the destination
buffer appears to be the matching size of "num_trips * sizeof(struct
thermal_trip)".
Hopefully that helps! If not, I can try again. :)
-Kees
--
Kees Cook
next prev parent reply other threads:[~2024-02-27 16:26 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-27 0:54 [PATCH] thermal: core: Move initial num_trips assignment before memcpy() Nathan Chancellor
2024-02-27 2:08 ` Kees Cook
2024-02-27 11:07 ` Rafael J. Wysocki
2024-02-27 9:58 ` Lukasz Luba
2024-02-27 10:14 ` Daniel Lezcano
2024-02-27 11:09 ` Rafael J. Wysocki
2024-02-27 15:37 ` Daniel Lezcano
2024-02-27 16:26 ` Kees Cook [this message]
2024-02-27 16:47 ` Daniel Lezcano
2024-02-27 17:00 ` Kees Cook
2024-02-28 8:41 ` Lukasz Luba
2024-02-28 16:56 ` Nathan Chancellor
2024-02-28 17:48 ` Kees Cook
2024-02-29 7:42 ` Lukasz Luba
2024-02-27 16:26 ` Nathan Chancellor
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=202402270816.0EA3349A76@keescook \
--to=keescook@chromium.org \
--cc=daniel.lezcano@linaro.org \
--cc=gustavoars@kernel.org \
--cc=justinstitt@google.com \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=llvm@lists.linux.dev \
--cc=lukasz.luba@arm.com \
--cc=morbo@google.com \
--cc=nathan@kernel.org \
--cc=patches@lists.linux.dev \
--cc=rafael@kernel.org \
--cc=rui.zhang@intel.com \
--cc=stanislaw.gruszka@linux.intel.com \
/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.