* Query Regarding Stack-Out-of-Bounds Error
@ 2024-08-26 12:34 Muni Sekhar
2024-08-26 19:46 ` Valdis Klētnieks
0 siblings, 1 reply; 4+ messages in thread
From: Muni Sekhar @ 2024-08-26 12:34 UTC (permalink / raw)
To: kernelnewbies; +Cc: LKML
Dear Linux Kernel Community,
I am writing to seek clarification on a potential stack-out-of-bounds
issue observed during the calls to for_each_set_bit function or
find_first_bit function, specifically in the following code snippet:
static struct cmd_info *find_cmd_entry_any_ring(struct intel_gvt *gvt,
unsigned int opcode, int rings)
{
struct cmd_info *info = NULL;
unsigned int ring;
...
for_each_set_bit(ring, (unsigned long *)&rings, I915_NUM_ENGINES) {
In the above code, a 32-bit integer pointer (rings) is being cast to a
64-bit unsigned long pointer, which leads to an extra 4 bytes being
accessed. This raises a concern regarding a stack-out-of-bounds bug.
My specific query is: While it is logically understandable that a
write operation involving these extra 4 bytes could cause a kernel
crash, in this case, it is a read operation that is occurring. Would
such a read operation still be capable of crashing the kernel or
resulting in unpredictable system behaviour? If so, could you please
explain how that would happen?
I appreciate your insights and look forward to your guidance on this issue.
--
Thanks,
Sekhar
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Query Regarding Stack-Out-of-Bounds Error
2024-08-26 12:34 Query Regarding Stack-Out-of-Bounds Error Muni Sekhar
@ 2024-08-26 19:46 ` Valdis Klētnieks
2024-08-27 10:31 ` Muni Sekhar
2024-08-31 17:19 ` Muni Sekhar
0 siblings, 2 replies; 4+ messages in thread
From: Valdis Klētnieks @ 2024-08-26 19:46 UTC (permalink / raw)
To: Muni Sekhar; +Cc: LKML, kernelnewbies
On Mon, 26 Aug 2024 18:04:39 +0530, Muni Sekhar said:
> static struct cmd_info *find_cmd_entry_any_ring(struct intel_gvt *gvt,
> unsigned int opcode, int rings)
> {
> struct cmd_info *info = NULL;
> unsigned int ring;
> ...
> for_each_set_bit(ring, (unsigned long *)&rings, I915_NUM_ENGINES) {
>
> In the above code, a 32-bit integer pointer (rings) is being cast to a
> 64-bit unsigned long pointer, which leads to an extra 4 bytes being
> accessed. This raises a concern regarding a stack-out-of-bounds bug.
>
> My specific query is: While it is logically understandable that a
> write operation involving these extra 4 bytes could cause a kernel
> crash, in this case, it is a read operation that is occurring.
Note that 'ring' is located in the stack frame for the current function. So to
complete the analysis - is there any way that the stack frame can be located in
such a way that 'ring' is the *very last* 4 bytes on a page, and the next page
*isn't* allocated, *and* I915_NUM_ENGINES is big enough to cause the loop to walk
off the end?
For bonus points, part 1: Does the answer depend on whether the architecture
has stacks that grow up, or grow down in address?
For bonus points, part 2: can this function be called quickly enough, and
enough times, that it can be abused to do something interesting to L1/L2 cache
and speculative execution, because some systems will fetch not only the bytes
needed, but as much as 64 or 128 bytes of cache line? Can you name 3 security
bugs that abused this sort of thing?
Free hint: There's a bit of interesting code in kernel/exit.c that tells you if
your system has gotten close to running out of kernel stack.
[/usr/src/linux-next] dmesg | grep 'greatest stack'
[ 1.093400] [ T40] pgdatinit0 (40) used greatest stack depth: 13920 bytes left
[ 3.832907] [ T82] modprobe (82) used greatest stack depth: 8 bytes left
Hmm... wonder how that modprobe managed *that* :)
\0\0\0\0\0\0\0\0
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Query Regarding Stack-Out-of-Bounds Error
2024-08-26 19:46 ` Valdis Klētnieks
@ 2024-08-27 10:31 ` Muni Sekhar
2024-08-31 17:19 ` Muni Sekhar
1 sibling, 0 replies; 4+ messages in thread
From: Muni Sekhar @ 2024-08-27 10:31 UTC (permalink / raw)
To: Valdis Klētnieks; +Cc: LKML, kernelnewbies
On Tue, Aug 27, 2024 at 1:16 AM Valdis Klētnieks
<valdis.kletnieks@vt.edu> wrote:
>
> On Mon, 26 Aug 2024 18:04:39 +0530, Muni Sekhar said:
>
> > static struct cmd_info *find_cmd_entry_any_ring(struct intel_gvt *gvt,
> > unsigned int opcode, int rings)
> > {
> > struct cmd_info *info = NULL;
> > unsigned int ring;
> > ...
> > for_each_set_bit(ring, (unsigned long *)&rings, I915_NUM_ENGINES) {
> >
> > In the above code, a 32-bit integer pointer (rings) is being cast to a
> > 64-bit unsigned long pointer, which leads to an extra 4 bytes being
> > accessed. This raises a concern regarding a stack-out-of-bounds bug.
> >
> > My specific query is: While it is logically understandable that a
> > write operation involving these extra 4 bytes could cause a kernel
> > crash, in this case, it is a read operation that is occurring.
>
> Note that 'ring' is located in the stack frame for the current function. So to
> complete the analysis - is there any way that the stack frame can be located in
> such a way that 'ring' is the *very last* 4 bytes on a page, and the next page
> *isn't* allocated, *and* I915_NUM_ENGINES is big enough to cause the loop to walk
> off the end?
>
> For bonus points, part 1: Does the answer depend on whether the architecture
> has stacks that grow up, or grow down in address?
Stack Frame Example
|---------------------------|
| Return Address |
|---------------------------|
| Saved Frame Pointer |
|---------------------------|
| Parameter: gvt |
|---------------------------|
| Parameter: opcode |
|---------------------------|
| Parameter: rings |
|---------------------------|
| Local Variable: info |
|---------------------------|
| Local Variable: ring |
|---------------------------|
If the stack grows downwards, the previous 32 bits (4 bytes) before
rings will be read as part of the 64-bit value.
If the stack grows upwards, the next 32 bits (4 bytes) after rings
will be read as part of the 64-bit value.
Consider that the stack grows upwards and the "ring" variable is
located at the very end of a stack page. What should be the value of
I915_NUM_ENGINES to trigger the Stack-Out-of-Bounds crash?
>
> For bonus points, part 2: can this function be called quickly enough, and
> enough times, that it can be abused to do something interesting to L1/L2 cache
> and speculative execution, because some systems will fetch not only the bytes
> needed, but as much as 64 or 128 bytes of cache line? Can you name 3 security
> bugs that abused this sort of thing?
>
> Free hint: There's a bit of interesting code in kernel/exit.c that tells you if
> your system has gotten close to running out of kernel stack.
>
> [/usr/src/linux-next] dmesg | grep 'greatest stack'
> [ 1.093400] [ T40] pgdatinit0 (40) used greatest stack depth: 13920 bytes left
> [ 3.832907] [ T82] modprobe (82) used greatest stack depth: 8 bytes left
>
> Hmm... wonder how that modprobe managed *that* :)
>
>
>
--
Thanks,
Sekhar
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Query Regarding Stack-Out-of-Bounds Error
2024-08-26 19:46 ` Valdis Klētnieks
2024-08-27 10:31 ` Muni Sekhar
@ 2024-08-31 17:19 ` Muni Sekhar
1 sibling, 0 replies; 4+ messages in thread
From: Muni Sekhar @ 2024-08-31 17:19 UTC (permalink / raw)
To: Valdis Klētnieks; +Cc: LKML, kernelnewbies
On Tue, Aug 27, 2024 at 1:16 AM Valdis Klētnieks
<valdis.kletnieks@vt.edu> wrote:
>
> On Mon, 26 Aug 2024 18:04:39 +0530, Muni Sekhar said:
>
> > static struct cmd_info *find_cmd_entry_any_ring(struct intel_gvt *gvt,
> > unsigned int opcode, int rings)
> > {
> > struct cmd_info *info = NULL;
> > unsigned int ring;
> > ...
> > for_each_set_bit(ring, (unsigned long *)&rings, I915_NUM_ENGINES) {
> >
> > In the above code, a 32-bit integer pointer (rings) is being cast to a
> > 64-bit unsigned long pointer, which leads to an extra 4 bytes being
> > accessed. This raises a concern regarding a stack-out-of-bounds bug.
> >
> > My specific query is: While it is logically understandable that a
> > write operation involving these extra 4 bytes could cause a kernel
> > crash, in this case, it is a read operation that is occurring.
>
> Note that 'ring' is located in the stack frame for the current function. So to
> complete the analysis - is there any way that the stack frame can be located in
> such a way that 'ring' is the *very last* 4 bytes on a page, and the next page
> *isn't* allocated, *and* I915_NUM_ENGINES is big enough to cause the loop to walk
> off the end?
>
> For bonus points, part 1: Does the answer depend on whether the architecture
> has stacks that grow up, or grow down in address?
Here’s an example stack frame for context:
|---------------------------|
| Return Address |
|---------------------------|
| Saved Frame Pointer |
|---------------------------|
| Parameter: gvt |
|---------------------------|
| Parameter: opcode |
|---------------------------|
| Parameter: rings |
|---------------------------|
| Local Variable: info |
|---------------------------|
| Local Variable: ring |
|---------------------------|
Stack Growth Downwards:
If the stack grows downward in address space, is there any scenario
where the stack frame could be positioned such that the return address
is located at the very last 4 bytes of a page, the next page isn't
allocated, and I915_NUM_ENGINES is large enough to cause the loop to
walk off the end? If this happens, would it result in a
stack-out-of-bounds error leading to a kernel crash?
Stack Growth Upwards:
Conversely, if the stack grows upward, could the stack frame be
positioned in such a way that the 'ring' variable is at the very last
4 bytes of a page, and the next page isn’t allocated, with
I915_NUM_ENGINES being large enough to cause the loop to walk off the
end? Would this also result in a stack-out-of-bounds error causing a
kernel crash?
I'm curious as to why the likelihood of this error seems to depend on
whether the architecture has stacks that grow up or down in address
space. In both scenarios stack-out-of-bounds error behaves the same,
right?
>
> For bonus points, part 2: can this function be called quickly enough, and
> enough times, that it can be abused to do something interesting to L1/L2 cache
> and speculative execution, because some systems will fetch not only the bytes
> needed, but as much as 64 or 128 bytes of cache line? Can you name 3 security
> bugs that abused this sort of thing?
Where should I look to find more details about these security bugs?
I appreciate your insights on these questions.
>
> Free hint: There's a bit of interesting code in kernel/exit.c that tells you if
> your system has gotten close to running out of kernel stack.
>
> [/usr/src/linux-next] dmesg | grep 'greatest stack'
> [ 1.093400] [ T40] pgdatinit0 (40) used greatest stack depth: 13920 bytes left
> [ 3.832907] [ T82] modprobe (82) used greatest stack depth: 8 bytes left
>
> Hmm... wonder how that modprobe managed *that* :)
>
>
>
--
Thanks,
Sekhar
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-08-31 17:20 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-26 12:34 Query Regarding Stack-Out-of-Bounds Error Muni Sekhar
2024-08-26 19:46 ` Valdis Klētnieks
2024-08-27 10:31 ` Muni Sekhar
2024-08-31 17:19 ` Muni Sekhar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).