diff options
| author | Jinke Han <jinkehan@didiglobal.com> | 2026-09-08 15:37:42 +0800 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2026-09-17 09:48:42 +0200 |
| commit | a5f7a5bb3b7f28ba7e4fa246775b29a0e5537255 (patch) | |
| tree | 73fef824f9a846cf935869d0dbc5070ef6e2f741 /Documentation/driver-api/spi.rst | |
| download | linux-stable-a5f7a5bb3b7f28ba7e4fa246775b29a0e5537255.tar.gz linux-stable-a5f7a5bb3b7f28ba7e4fa246775b29a0e5537255.zip | |
x86/kprobes: Fix crash when probing CS CALL instructionsgrafted
When using eBPF to probe CS CALL instructions within a function,
a crash can be triggered.
The eBPF tool probes offset 257 of the __hrtimer_run_queues()
function:
<__hrtimer_run_queues+249>: nopl 0x0(%rax,%rax,1)
<__hrtimer_run_queues+254>: mov %r14,%rdi
<__hrtimer_run_queues+257>: cs call <__x86_indirect_thunk_r12>
<__hrtimer_run_queues+263>: mov %eax,%r12d
<__hrtimer_run_queues+266>: xchg %ax,%ax
<__hrtimer_run_queues+268>: mov %r13,%rdi
Which triggers this crash:
BUG: unable to handle page fault for address: 00000000000f41c9
#PF: supervisor write access in kernel mode
#PF: error_code(0x0002) - not-present page
PGD 0 P4D 0
Oops: 0002 [#1] SMP NOPTI
CPU: 1 PID: 0 Comm: swapper/1 Kdump: loaded Tainted: P
RIP: 0010:__hrtimer_run_queues+0x106/0x230
Note that __hrtimer_run_queues+0x106 is __hrtimer_run_queues+262, which is
at the 6th byte of the above CS CALL instruction. Since the CS CALL
instruction occupies 6 bytes, the exception occurred in the middle of that
call instruction.
The root cause is that when using eBPF tools to probe in the middle of a
function, a kprobe with INT3 is used as the underlying implementation.
During single-step emulation of the original CALL instruction,
int3_emulate_call() assumes that the probed CALL instruction is 5 bytes
long. However, the actual CS-prefixed CALL instruction occupies 6 bytes,
so it constructs an incorrect exception return address. When the CPU
returns from the kprobe handler, the next instruction to be executed is at
the address of the last byte of that CS CALL instruction. Coincidentally,
starting from that address, the CPU fetches and decodes a completely
different instruction, which ultimately triggers a kernel crash.
Fix the issue by using the actual instruction length obtained from
the instruction decoder when constructing the exception return
address, rather than relying on the hardcoded CALL_INSN_SIZE macro.
[ mingo: Refined the changelog ]
Fixes: 6256e668b7af ("x86/kprobes: Use int3 instead of debug trap for single-step")
Suggested-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Jinke Han <jinkehan@didiglobal.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Acked-by: Yafang Shao <laoar.shao@gmail.com>
Acked-by: Borislav Petkov <bp@alien8.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://patch.msgid.link/20260908073742.GA10517@didi-ThinkCentre-M920t-N000
Diffstat (limited to 'Documentation/driver-api/spi.rst')
| -rw-r--r-- | Documentation/driver-api/spi.rst | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/Documentation/driver-api/spi.rst b/Documentation/driver-api/spi.rst new file mode 100644 index 000000000..74eca6735 --- /dev/null +++ b/Documentation/driver-api/spi.rst @@ -0,0 +1,53 @@ +Serial Peripheral Interface (SPI) +================================= + +SPI is the "Serial Peripheral Interface", widely used with embedded +systems because it is a simple and efficient interface: basically a +multiplexed shift register. Its three signal wires hold a clock (SCK, +often in the range of 1-20 MHz), a "Master Out, Slave In" (MOSI) data +line, and a "Master In, Slave Out" (MISO) data line. SPI is a full +duplex protocol; for each bit shifted out the MOSI line (one per clock) +another is shifted in on the MISO line. Those bits are assembled into +words of various sizes on the way to and from system memory. An +additional chipselect line is usually active-low (nCS); four signals are +normally used for each peripheral, plus sometimes an interrupt. + +The SPI bus facilities listed here provide a generalized interface to +declare SPI buses and devices, manage them according to the standard +Linux driver model, and perform input/output operations. At this time, +only "master" side interfaces are supported, where Linux talks to SPI +peripherals and does not implement such a peripheral itself. (Interfaces +to support implementing SPI slaves would necessarily look different.) + +The programming interface is structured around two kinds of driver, and +two kinds of device. A "Controller Driver" abstracts the controller +hardware, which may be as simple as a set of GPIO pins or as complex as +a pair of FIFOs connected to dual DMA engines on the other side of the +SPI shift register (maximizing throughput). Such drivers bridge between +whatever bus they sit on (often the platform bus) and SPI, and expose +the SPI side of their device as a :c:type:`struct spi_controller +<spi_controller>`. SPI devices are children of that master, +represented as a :c:type:`struct spi_device <spi_device>` and +manufactured from :c:type:`struct spi_board_info +<spi_board_info>` descriptors which are usually provided by +board-specific initialization code. A :c:type:`struct spi_driver +<spi_driver>` is called a "Protocol Driver", and is bound to a +spi_device using normal driver model calls. + +The I/O model is a set of queued messages. Protocol drivers submit one +or more :c:type:`struct spi_message <spi_message>` objects, +which are processed and completed asynchronously. (There are synchronous +wrappers, however.) Messages are built from one or more +:c:type:`struct spi_transfer <spi_transfer>` objects, each of +which wraps a full duplex SPI transfer. A variety of protocol tweaking +options are needed, because different chips adopt very different +policies for how they use the bits transferred with SPI. + +.. kernel-doc:: include/linux/spi/spi.h + :internal: + +.. kernel-doc:: drivers/spi/spi.c + :functions: spi_register_board_info + +.. kernel-doc:: drivers/spi/spi.c + :export: |
