]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
media: solo6x10: Check for out of bounds chip_id
authorKees Cook <kees@kernel.org>
Fri, 12 Dec 2025 03:00:35 +0000 (19:00 -0800)
committerHans Verkuil <hverkuil+cisco@kernel.org>
Tue, 13 Jan 2026 12:21:03 +0000 (13:21 +0100)
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
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]

drivers/media/pci/solo6x10/solo6x10-tw28.c

index 1b7c22a9bc94f133a5d3dc00218577a1238a9c7a..8f53946c67928f9bac331d07481651060fe44114 100644 (file)
@@ -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 */