From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Kees Cook <kees@kernel.org>,
Nathan Chancellor <nathan@kernel.org>,
Hans Verkuil <hverkuil+cisco@kernel.org>,
Sasha Levin <sashal@kernel.org>,
maintainers@bluecherrydvr.com, andrey_utkin@fastmail.com,
ismael@iodev.co.uk, linux-media@vger.kernel.org,
llvm@lists.linux.dev
Subject: [PATCH AUTOSEL 6.19-5.10] media: solo6x10: Check for out of bounds chip_id
Date: Fri, 13 Feb 2026 19:59:09 -0500 [thread overview]
Message-ID: <20260214010245.3671907-69-sashal@kernel.org> (raw)
In-Reply-To: <20260214010245.3671907-1-sashal@kernel.org>
From: Kees Cook <kees@kernel.org>
[ Upstream commit 0fdf6323c35a134f206dcad5babb4ff488552076 ]
Clang with CONFIG_UBSAN_SHIFT=y noticed a condition where a signed type
(literal "1" is an "int") could end up being shifted beyond 32 bits,
so instrumentation was added (and due to the double is_tw286x() call
seen via inlining), Clang decides the second one must now be undefined
behavior and elides the rest of the function[1]. This is a known problem
with Clang (that is still being worked on), but we can avoid the entire
problem by actually checking the existing max chip ID, and now there is
no runtime instrumentation added at all since everything is known to be
within bounds.
Additionally use an unsigned value for the shift to remove the
instrumentation even without the explicit bounds checking.
Link: https://github.com/ClangBuiltLinux/linux/issues/2144 [1]
Suggested-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Kees Cook <kees@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
[hverkuil: fix checkpatch warning for is_tw286x]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Analysis of media: solo6x10: Check for out of bounds chip_id
### 1. Commit Message Analysis
The commit addresses two related issues:
- **UBSAN shift sanitizer warning**: With `CONFIG_UBSAN_SHIFT=y`, Clang
detects that a signed `int` literal `1` could be shifted beyond 32
bits in the `is_tw286x()` macro, which is undefined behavior (UB).
- **Clang miscompilation due to UB**: Because of the UB, Clang's
optimizer concludes the second `is_tw286x()` call (after inlining)
must be UB and **elides the rest of the function**. This means code is
silently dropped by the compiler.
- The fix adds explicit bounds checking (`chip_num >= TW_NUM_CHIP`) and
changes the shift to use an unsigned value (`1U`).
### 2. Code Change Analysis
Three distinct changes:
**a) Macro fix (`1` → `1U` and added parentheses):**
```c
-#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
+#define is_tw286x(__solo, __id) (!((__solo)->tw2815 & (1U << (__id))))
```
- Changes signed shift to unsigned, eliminating undefined behavior for
shifts ≥ 31
- Adds proper parenthesization (macro hygiene)
- This is a real UB fix — shifting a signed `1` by ≥ 31 bits is
undefined in C
**b) Bounds check in `tw28_set_ctrl_val()`:**
```c
+ if (chip_num >= TW_NUM_CHIP)
+ return -EINVAL;
```
- `chip_num` is derived from `ch / 4` where `ch` is a `u8` parameter
- `TW_NUM_CHIP` defines the maximum number of chips
- Without this check, an out-of-bounds `chip_num` would cause UB in the
`is_tw286x()` shift and potentially out-of-bounds array access in
`TW_CHIP_OFFSET_ADDR()`
**c) Same bounds check in `tw28_get_ctrl_val()`:**
```c
+ if (chip_num >= TW_NUM_CHIP)
+ return -EINVAL;
```
- Same protection for the read path
### 3. Bug Classification
This fixes **undefined behavior** that leads to **compiler-caused
miscompilation**. The Clang compiler, upon detecting that UB is
possible, optimizes away portions of the function. This is not a
theoretical concern — the linked ClangBuiltLinux issue (#2144) documents
the actual problem.
The consequences of the UB:
1. **Silent code elision**: The compiler removes code paths it deems
unreachable due to UB, meaning the function silently does nothing in
some cases
2. **Potential out-of-bounds access**: Without bounds checking, invalid
`chip_id` values cause shifts beyond type width
3. **UBSAN runtime warnings**: Noise in kernel logs for users with
sanitizers enabled
### 4. Scope and Risk Assessment
- **Files changed**: 1 file (`solo6x10-tw28.c`)
- **Lines changed**: ~6 lines of actual logic (macro change + 2 bounds
checks)
- **Risk**: Very low — the macro change preserves semantics while
removing UB; bounds checks add early returns for invalid inputs
- **Subsystem**: Media PCI driver (solo6x10) — contained, no core kernel
impact
- **Could break something**: Extremely unlikely — the macro change only
affects behavior for previously-UB cases, and the bounds checks only
reject invalid chip IDs
### 5. User Impact
- Users building with Clang + UBSAN (increasingly common, especially on
Android and ChromeOS) hit this directly
- The miscompilation affects correctness of the driver — functions may
be silently broken
- The solo6x10 is a surveillance/DVR capture card used in production
systems
### 6. Stable Kernel Criteria
| Criterion | Assessment |
|-----------|------------|
| Obviously correct | Yes — straightforward UB fix and bounds check |
| Fixes real bug | Yes — compiler miscompilation due to UB |
| Important issue | Medium — affects Clang users, prevents silent code
elision |
| Small and contained | Yes — 6 lines of logic in 1 file |
| No new features | Correct — pure bug fix |
| Tested | Yes — authored by Kees Cook, reviewed/applied by Hans Verkuil
|
### 7. Dependencies
The patch is self-contained. It only references `TW_NUM_CHIP` which is
already defined in the driver header. No dependencies on other commits.
### Decision
This is a legitimate bug fix addressing undefined behavior that causes
real miscompilation with Clang. The fix is small (6 lines of logic),
surgical, self-contained, obviously correct, and authored/reviewed by
well-known kernel developers. It prevents silent code elision by the
compiler and adds proper bounds checking. The risk of regression is
negligible.
**YES**
drivers/media/pci/solo6x10/solo6x10-tw28.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/media/pci/solo6x10/solo6x10-tw28.c b/drivers/media/pci/solo6x10/solo6x10-tw28.c
index 1b7c22a9bc94f..8f53946c67928 100644
--- a/drivers/media/pci/solo6x10/solo6x10-tw28.c
+++ b/drivers/media/pci/solo6x10/solo6x10-tw28.c
@@ -166,7 +166,7 @@ static const u8 tbl_tw2865_pal_template[] = {
0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
};
-#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
+#define is_tw286x(__solo, __id) (!((__solo)->tw2815 & (1U << (__id))))
static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
u8 tw_off)
@@ -686,6 +686,9 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
chip_num = ch / 4;
ch %= 4;
+ if (chip_num >= TW_NUM_CHIP)
+ return -EINVAL;
+
if (val > 255 || val < 0)
return -ERANGE;
@@ -758,6 +761,9 @@ int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
chip_num = ch / 4;
ch %= 4;
+ if (chip_num >= TW_NUM_CHIP)
+ return -EINVAL;
+
switch (ctrl) {
case V4L2_CID_SHARPNESS:
/* Only 286x has sharpness */
--
2.51.0
next prev parent reply other threads:[~2026-02-14 1:05 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-14 0:58 [PATCH AUTOSEL 6.19-6.12] media: ipu6: Close firmware streams on streaming enable failure Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.12] media: chips-media: wave5: Fix conditional in start_streaming Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.12] media: mt9m114: Avoid a reset low spike during probe() Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.1] media: amphion: Clear last_buffer_dequeued flag for DEC_CMD_START Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-5.10] media: adv7180: fix frame interval in progressive mode Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.6] media: v4l2-async: Fix error handling on steps after finding a match Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.1] media: rkisp1: Fix filter mode register configuration Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.12] media: ipu6: Ensure stream_mutex is acquired when dealing with node list Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.12] media: mt9m114: Return -EPROBE_DEFER if no endpoint is found Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-6.18] media: uvcvideo: Create an ID namespace for streaming output terminals Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-6.12] media: ipu6: Always close firmware stream Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-6.18] media: qcom: camss: Do not enable cpas fast ahb clock for SM8550 VFE lite Sasha Levin
2026-02-14 0:59 ` Sasha Levin [this message]
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-6.18] drm/amdgpu: Refactor amdgpu_gem_va_ioctl for Handling Last Fence Update and Timeline Management v4 Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-6.12] media: chips-media: wave5: Process ready frames when CMD_STOP sent to Encoder Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-5.10] media: pvrusb2: fix URB leak in pvr2_send_request_ex Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-5.10] media: dvb-core: dmxdevfilter must always flush bufs Sasha Levin
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=20260214010245.3671907-69-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=andrey_utkin@fastmail.com \
--cc=hverkuil+cisco@kernel.org \
--cc=ismael@iodev.co.uk \
--cc=kees@kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=llvm@lists.linux.dev \
--cc=maintainers@bluecherrydvr.com \
--cc=nathan@kernel.org \
--cc=patches@lists.linux.dev \
--cc=stable@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox