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/iio/buffers.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/iio/buffers.rst')
| -rw-r--r-- | Documentation/driver-api/iio/buffers.rst | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/Documentation/driver-api/iio/buffers.rst b/Documentation/driver-api/iio/buffers.rst new file mode 100644 index 000000000..8779022e3 --- /dev/null +++ b/Documentation/driver-api/iio/buffers.rst @@ -0,0 +1,127 @@ +======= +Buffers +======= + +* struct iio_buffer — general buffer structure +* :c:func:`iio_validate_scan_mask_onehot` — Validates that exactly one channel + is selected +* :c:func:`iio_buffer_get` — Grab a reference to the buffer +* :c:func:`iio_buffer_put` — Release the reference to the buffer + +The Industrial I/O core offers a way for continuous data capture based on a +trigger source. Multiple data channels can be read at once from +:file:`/dev/iio:device{X}` character device node, thus reducing the CPU load. + +IIO buffer sysfs interface +========================== +An IIO buffer has an associated attributes directory under +:file:`/sys/bus/iio/devices/iio:device{X}/buffer/*`. Here are some of the +existing attributes: + +* :file:`length`, the total number of data samples (capacity) that can be + stored by the buffer. +* :file:`enable`, activate buffer capture. + +IIO buffer setup +================ + +The meta information associated with a channel reading placed in a buffer is +called a scan element. The important bits configuring scan elements are +exposed to userspace applications via the +:file:`/sys/bus/iio/devices/iio:device{X}/scan_elements/` directory. This +directory contains attributes of the following form: + +* :file:`enable`, used for enabling a channel. If and only if its attribute + is non *zero*, then a triggered capture will contain data samples for this + channel. +* :file:`index`, the scan_index of the channel. +* :file:`type`, description of the scan element data storage within the buffer + and hence the form in which it is read from user space. + Format is [be|le]:[f|s|u]bits/storagebits[Xrepeat][>>shift] . + + * *be* or *le*, specifies big or little endian. + * *f*, specifies if floating-point. + * *s* or *u*, specifies if signed (2's complement) or unsigned. + * *bits*, is the number of valid data bits. + * *storagebits*, is the number of bits (after padding) that it occupies in the + buffer. + * *repeat*, specifies the number of bits/storagebits repetitions. When the + repeat element is 0 or 1, then the repeat value is omitted. + * *shift*, if specified, is the shift that needs to be applied prior to + masking out unused bits. + +For example, a driver for a 3-axis accelerometer with 12 bit resolution where +data is stored in two 8-bits registers as follows:: + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + |D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06) + +---+---+---+---+---+---+---+---+ + + 7 6 5 4 3 2 1 0 + +---+---+---+---+---+---+---+---+ + |D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07) + +---+---+---+---+---+---+---+---+ + +will have the following scan element type for each axis:: + + $ cat /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_type + le:s12/16>>4 + +A user space application will interpret data samples read from the buffer as +two byte little endian signed data, that needs a 4 bits right shift before +masking out the 12 valid bits of data. + +For implementing buffer support a driver should initialize the following +fields in iio_chan_spec definition:: + + struct iio_chan_spec { + /* other members */ + int scan_index + struct { + char format; + u8 realbits; + u8 storagebits; + u8 shift; + u8 repeat; + enum iio_endian endianness; + } scan_type; + }; + +The driver implementing the accelerometer described above will have the +following channel definition:: + + struct iio_chan_spec accel_channels[] = { + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X, + /* other stuff here */ + .scan_index = 0, + .scan_type = { + .format = IIO_SCAN_FORMAT_SIGNED_INT, + .realbits = 12, + .storagebits = 16, + .shift = 4, + .endianness = IIO_LE, + }, + } + /* similar for Y (with channel2 = IIO_MOD_Y, scan_index = 1) + * and Z (with channel2 = IIO_MOD_Z, scan_index = 2) axis + */ + } + +Here **scan_index** defines the order in which the enabled channels are placed +inside the buffer. Channels with a lower **scan_index** will be placed before +channels with a higher index. Each channel needs to have a unique +**scan_index**. + +Setting **scan_index** to -1 can be used to indicate that the specific channel +does not support buffered capture. In this case no entries will be created for +the channel in the scan_elements directory. + +More details +============ +.. kernel-doc:: include/linux/iio/buffer.h +.. kernel-doc:: drivers/iio/industrialio-buffer.c + :export: |
