Re: [Linux-kernel-mentees] [PATCH] v4l2-tpg: Fix global-out-of-bounds read in precalculate_color()

From: Peilin Ye
Date: Fri Aug 21 2020 - 05:48:28 EST


Hi Mr. Verkuil,

On Wed, Aug 19, 2020 at 04:26:28PM +0200, Hans Verkuil wrote:
> Hi Peilin,
>
> On 10/08/2020 07:05, Peilin Ye wrote:
> > precalculate_color() is reading out of `sin` since `tpg->hue` is not being
> > properly checked. Fix it. `cos` is safe, as long as `tpg->hue` is higher
> > than or equal to -192.
>
> Thank you for this patch, but there is something I don't understand, namely
> just *how* tpg->hue can be out-of-range.
>
> From what I can see vivid sets hue via tpg_s_hue() when the V4L2_CID_HUE control
> is set. But that control has a range of -128...128, so ctrl->val should always be in
> that range.
>
> I would really like to know 1) what the value of tpg->hue actually is when it goes
> out of range, and 2) who is changing it to that value. Can you do a bit more digging?

The value of `tpg->hue` was -20551. It came from the userspace, see the
"\xb9\xaf" on line 500 of the reproducer:

https://syzkaller.appspot.com/text?tag=ReproC&x=14b49e71e00000

NONFAILING(memcpy((void*)0x20000200, "/dev/video6\000\000", 13));
res = syscall(__NR_openat, 0xffffffffffffff9cul, 0x20000200ul, 2ul, 0ul);
if (res != -1)
r[0] = res;
NONFAILING(memcpy((void*)0x20000140,
"\x4d\x43\x66\x34\xfd\x89\xb9\xaf\x0d\x59\xa2\x83\x4c\xfd"
^^^^ ^^^^ ^^^^ ^^^^^^^^
"\x3e\x64\x7c\x96\xcd\x59\xf2\x3a\x18\xa3\x81\x49\x22\xc0"
"\xc1\xbf\x02\xa5\x50\x5f\xcb\x48\x92\x0e\xf3\xdc\xff\x85"
"\xb7\x84\x21\xab\xef\x31\x3d\xb1\xb6\x5d\xbf\x07\x8e\xee"
"\x5e\x7c\x73\x32\xf4\x9d\x1e\x62\x6b\x6a\xa0\x74\x73\xe6"
"\xca\x1b\xdb\x7a\xca\x76\xd8\x37\xb8\xd9",
80));
syscall(__NR_write, r[0], 0x20000140ul, 8ul);

I guess the root cause is a race condition in the vivid test driver,
which completely corrupted `tpg`. I see bytes like "\x4d", "\x66" and
"\xfd" around `tpg->hue`, too.

The reproducer does two things: the above write() on /dev/video6, and a
preadv() on /dev/video3:

NONFAILING(*(uint64_t*)0x20000800 = 0x20000000);
NONFAILING(*(uint64_t*)0x20000808 = 0x1f);
NONFAILING(*(uint64_t*)0x20000810 = 0);
NONFAILING(*(uint64_t*)0x20000818 = 0);
NONFAILING(*(uint64_t*)0x20000820 = 0);
NONFAILING(*(uint64_t*)0x20000828 = 0);
NONFAILING(*(uint64_t*)0x20000830 = 0);
NONFAILING(*(uint64_t*)0x20000838 = 0);
NONFAILING(*(uint64_t*)0x20000840 = 0);
NONFAILING(*(uint64_t*)0x20000848 = 0);
syscall(__NR_preadv, r[1], 0x20000800ul, 5ul, 0ul);

I commented out this preadv(), then the reproducer didn't cause any
crash. Unfortunately I don't know the code well enough in order to
figure out exactly why...At this point of time I'd like to send you an
v2 as you suggested, it should work as a mitigation.

Thank you for the suggestion!

Peilin Ye