| 0/0 |
2026/07/30 11:51 |
flow |
repro |
1h44m
Error:
|
| 1/1 |
2026/07/30 11:51 |
action |
kernel-checkouter |
0m
Results: map[KernelSrc:/app/workdir/cache/src/a43694d4bed4bc357b0c64e52341ff394417331e]
|
| 2/1 |
2026/07/30 11:51 |
action |
kernel-builder |
15m
Results: map[KernelObj:/app/workdir/cache/build/787006d70b5d139dff241ae139a6dba39841260e]
|
| 3/1 |
2026/07/30 12:07 |
action |
codesearch-prepare |
10m
Results: map[Index:codesearch-index]
|
| 4/1 |
2026/07/30 12:17 |
agent |
crash-repro-finder |
1h18m
Model:
Error:
Instruction:
You are an expert in Linux kernel fuzzing. Your goal is to write a syzkaller program to trigger a specific bug.
Execution sandboxes ('Sandbox' output field):
- "none": Runs test processes as root without Linux namespace isolation (PID, Net, IPC, User).
- "setuid": Runs test processes under unprivileged user accounts (drops root privileges and capabilities).
- "namespace": Runs test processes inside isolated Linux namespaces
(CLONE_NEWNS, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWPID, CLONE_NEWNET,
CLONE_NEWUSER) with isolated network devices (loopback, tun, etc.).
Use this for network, IPC, or namespace bugs.
- "android": Simulates Android application privilege and SELinux restrictions (drops privileges to Android UIDs/GIDs).
Document about syzkaller program syntax:
===
# Program syntax
Syzkaller uses a compact domain-specific language (DSL) for programs
to log executed programs, test its code, and persist programs in the
corpus. This page provides a brief description of the corresponding
syntax. Some useful information can also be found in the
[existing examples](/sys/linux/test) and in the program
[deserialization code](/prog/encoding.go).
Together with execution options, the DSL provides everything that
syz-executor needs to run a program.
For example, consider the program:
```
r0 = syz_open_dev$loop(&(0x7f00000011c0), 0x0, 0x0)
r1 = openat$6lowpan_control(0xffffffffffffff9c, &(0x7f00000000c0), 0x2, 0x0)
ioctl$LOOP_SET_FD(r0, 0x4c00, r1)
```
Each line in this program describes a particular syscall invocation,
with the first two calls saving the result in temporary variables `r0`
and `r1`, which are passed to the third call.
```
line = assignment | call
assignment = variable " = " call
call = syscall-name "(" [arg ["," arg]*] ")" ["(" [call-prop ["," call-prop*] ")"]
arg = "nil" | "AUTO" | const-arg | resource-arg | result-arg | pointer-arg | string-arg | struct-arg | array-arg | union-arg
const-arg = integer
resource-arg = variable ["/" hex-integer] ["+" hex-integer]
result-arg = "<" variable "=>" arg
pointer-arg = "&" pointer-arg-addr ["=ANY"] "=" arg
pointer-arg-addr = "AUTO" | "(" pointer-addr ["/" region-size] ")"
string-arg = "'" escaped-string "'" | "\"" escaped-string "\"" | "\"$" escaped-string "\""
struct-arg = "{" [arg ["," arg]*] "}"
array-arg = "[" [arg ["," arg]*] "]"
union-arg = "@" field-name ["=" arg]
call-prop = prop-name ": " prop-value
variable = "r" dec-integer
pointer-addr = integer
region-size = integer
integer = dec-integer | oct-integer | "0x" hex-integer
```
Programs may also contain blank lines and comments.
```
# Obtain a file handle
r0 = openat(0xffffffffffffff9c, &AUTO='./file1\x00', 0x42, 0x1ff)
# Perform a write operation
write(r0, &AUTO="01010101", 0x4)
```
### Memory management
Memory management is performed by syzkaller itself. It will allocate
virtual memory regions of the necessary size and set the final values
of pointer arguments.
By using the `AUTO` keyword, programs can give syzkaller the full
control over storing the data. This may be convenient e.g. when a
parameter must be passed by reference, but the exact location of its
value is not of particular importance.
```
r1 = syz_genetlink_get_family_id$nl80211(&AUTO='nl80211\x00', 0xffffffffffffffff)
ioctl$sock_SIOCGIFINDEX_80211(r0, 0x8933, &AUTO={'wlan0\x00', <r2=>0x0})
```
Alternatively, some data can be "anchored" to specific addresses. It
may be especially important when a memory region must be shared
between multiple calls. In this case, pointer addresses must be given
at the 0x7f0000000000 offset. Before the actual execution, syzkaller
will adjust pointers to the start of the actual mmap'ed region.
### Call properties
Call properties specify extra information about how a specific call
must be executed. Each call within a program has its own set of call
properties. If no properties are provided, syzkaller takes the default
ones.
Currently, syzkaller supports the following call properties.
#### Fault injection
Syntax: `fail_nth: N`.
It takes an integer (base 10) argument `N`. If the argument is
non-negative, a fault will be injected into the `N`-th occasion.
```
r0 = openat$6lowpan_control(0xffffffffffffff9c, &(0x7f00000000c0), 0x2, 0x0)
ioctl$LOOP_SET_FD(r0, 0x4c00, r0) (fail_nth: 5)
```
#### Async
Syntax: `async`.
Instructs `syz-executor` not to wait until the call completes and
to proceed immediately to the next call.
```
r0 = openat(0xffffffffffffff9c, &AUTO='./file1\x00', 0x42, 0x1ff)
write(r0, &AUTO="01010101", 0x4) (async)
read(r0, &AUTO=""/4, 0x4)
close(r0)
```
When setting `async` flags be aware of the following considerations:
* Such programs should only be executed in threaded mode (i.e. `-threaded`
flag must be passed to `syz-executor`.
* Each `async` call is executed in a separate thread and there's a
limited number of available threads (`kMaxThreads = 16`).
* If an `async` call produces a resource, keep in mind that some other call
might take it as input and `syz-executor` will just pass 0 if the resource-
producing call has not finished by that time.
===
Document about syzlang system call descriptions syntax:
===
# Syscall description language
aka `syzlang` (`[siΛzΛlΓ¦Εg]`)
Pseudo-formal grammar of syscall description:
```
syscallname "(" [arg ["," arg]*] ")" [type] ["(" attribute* ")"]
arg = argname type
argname = identifier
type = typename [ "[" type-options "]" ]
typename = "const" | "intN" | "intptr" | "flags" | "array" | "ptr" |
"string" | "filename" | "glob" | "len" |
"bytesize" | "bytesizeN" | "bitsize" | "vma" | "proc" |
"compressed_image"
type-options = [type-opt ["," type-opt]]
```
common type-options include:
```
"opt" - the argument is optional (like mmap fd argument, or accept peer argument)
```
rest of the type-options are type-specific:
```
"const": integer constant, type-options:
value, underlying type (one of "intN", "intptr")
"intN"/"intptr": an integer without a particular meaning, type-options:
either an optional range of values (e.g. "5:10", or "100:200")
or a reference to flags description (see below),
or a single value
optionally followed by an alignment parameter if using a range
"flags": a set of values, type-options:
reference to flags description (see below), underlying int type (e.g. "int32")
"array": a variable/fixed-length array, type-options:
type of elements, optional size (fixed "5", or ranged "5:10", boundaries inclusive)
"ptr"/"ptr64": a pointer to an object, type-options:
direction (in/out/inout); type of the object
ptr64 has size of 8 bytes regardless of target pointer size
"string": a zero-terminated memory buffer (no pointer indirection implied), type-options:
either a string value in quotes for constant strings (e.g. "foo" or `deadbeef` for hex literal),
or a reference to string flags (special value `filename` produces file names),
optionally followed by a buffer size (string values will be padded with \x00 to that size)
"stringnoz": a non-zero-terminated memory buffer (no pointer indirection implied), type-options:
either a string value in quotes for constant strings (e.g. "foo" or `deadbeef` for hex literal),
or a reference to string flags,
"glob": glob pattern to match on the target files, type-options:
a pattern string in quotes (syntax: https://golang.org/pkg/path/filepath/#Match)
(e.g. "/sys/" or "/sys/**/*"),
or include exclude glob too (e.g. "/sys/**/*:-/sys/power/state")
"fmt": a string representation of an integer (not zero-terminated), type-options:
format (one of "dec", "hex", "oct") and the value (a resource, int, flags or proc)
the resulting data is always fixed-size (formatted as "%020llu", "0x%016llx" or "%023llo", respectively)
"len": length of another field (for array it is number of elements), type-options:
argname of the object
"bytesize": similar to "len", but always denotes the size in bytes, type-options:
argname of the object
"bitsize": similar to "len", but always denotes the size in bits, type-options:
argname of the object
"offsetof": offset of the field from the beginning of the parent struct, type-options:
field
"vma"/"vma64": a pointer to a set of pages (used as input for mmap/munmap/mremap/madvise), type-options:
optional number of pages (e.g. vma[7]), or a range of pages (e.g. vma[2-4])
vma64 has size of 8 bytes regardless of target pointer size
"proc": per process int (see description below), type-options:
value range start, how many values per process, underlying type
"compressed_image": zlib-compressed disk image
syscalls accepting compressed images must be marked with `no_generate`
and `no_minimize` call attributes. if the content of the decompressed image
can be checked by a `fsck`-like command, use the `fsck` syscall attribute
"text": machine code of the specified type, type-options:
text type (x86_real, x86_16, x86_32, x86_64, arm64)
"void": type with static size 0
mostly useful inside of templates and varlen unions, can't be syscall argument
```
flags/len/flags also have trailing underlying type type-option when used in structs/unions/pointers.
Flags are described as:
```
flagname = const ["," const]*
```
or for string flags as:
```
flagname = "\"" literal "\"" ["," "\"" literal "\""]*
```
Call attributes are:
```
"disabled": the call will not be used in fuzzing; useful to temporary disable some calls
or prohibit particular argument combinations.
"timeout[N]": additional execution timeout (in ms) for the call on top of some default value.
"prog_timeout[N]": additional execution timeout (in ms) for the whole program if it contains this call;
if a program contains several such calls, the max value is used.
"ignore_return": ignore return value of this syscall in fallback feedback; need to be used for calls
that don't return fixed error codes but rather something else (e.g. the current time).
"breaks_returns": ignore return values of all subsequent calls in the program in fallback feedback (can't be trusted).
"no_generate": do not try to generate this syscall, i.e. use only seed descriptions to produce it.
"no_minimize": do not modify instances of this syscall when trying to minimize a crashing program.
"no_squash": do not attempt to pass squashed arguments to this syscall.
Without that, the fuzzer will sometimes attempt to replace complex structures with arrays of bytes,
possibly triggering interesting mutations, but also making programs hard to reason about.
"fsck": the content of the compressed buffer argument for this syscall is a file system and the
string argument is a fsck-like command that will be called to verify the filesystem.
"remote_cover": wait longer to collect remote coverage for this call.
"kfuzz_test": the call is a kfuzztest target.
"snapshot": the call is enabled by default only in snapshot fuzzing mode, but can also be enabled in
the non-snasphot mode when listed in "enable_syscalls" with its full name (as opposed to a wildcard match).
It can also always be disabled via "disable_syscalls".
The attribute is generally used to mark calls that are not safe to execute in non-snapshot mode
(can lead to false positives, or lost connections to test machines.
```
## Ints
`int8`, `int16`, `int32` and `int64` denote an integer of the corresponding size.
`intptr` denotes a pointer-sized integer, i.e. C `long` type.
By appending `be` suffix (e.g. `int16be`) integers become big-endian.
It's possible to specify a range of values for an integer in the format of `int32[0:100]` or `int32[0:4096, 512]` for a 512-aligned int.
Integers can also take a reference to flags description or a value as its first type-option.
In that case, the alignment parameter is not supported.
To denote a bitfield of size N use `int64:N`.
It's possible to use these various kinds of ints as base types for `const`, `flags`, `len` and `proc`.
```
example_struct {
f0 int8 # random 1-byte integer
f1 const[0x42, int16be] # const 2-byte integer with value 0x4200 (big-endian 0x42)
f2 int32[0:100] # random 4-byte integer with values from 0 to 100 inclusive
f3 int32[1:10, 2] # random 4-byte integer with values {1, 3, 5, 7, 9}
f4 int64:20 # random 20-bit bitfield
f5 int8[10] # const 1-byte integer with value 10
f6 int32[flagname] # random 4-byte integer from the set of values referenced by flagname
}
```
## Structs
Structs are described as:
```
structname "{" "\n"
(fieldname type ("(" fieldattribute* ")")? (if[expression])? "\n")+
"}" ("[" attribute* "]")?
```
Fields can have attributes specified in parentheses after the field, independent
of their type. `in/out/inout` attribute specify per-field direction, for example:
```
foo {
field0 const[1, int32] (in)
field1 int32 (inout)
field2 fd (out)
}
```
You may specify conditions that determine whether a field will be included:
```
foo {
field0 int32
field1 int32 (if[value[field0] == 0x1])
}
```
See [the corresponding section](syscall_descriptions_syntax.md#conditional-fields)
for more details.
`out_overlay` attribute allows to have separate input and output layouts for the struct.
Fields before the `out_overlay` field are input, fields starting from `out_overlay` are output.
Input and output fields overlap in memory (both start from the beginning of the struct in memory).
For example:
```
foo {
in0 const[1, int32]
in1 flags[bar, int8]
in2 ptr[in, string]
out0 fd (out_overlay)
out1 int32
}
```
Structs can have attributes specified in square brackets after the struct.
Attributes are:
- `packed`: the struct does not have paddings between fields and has alignment 1; this is similar to GNU C `__attribute__((packed))`; struct alignment can be overridden with `align` attribute
- `align[N]`: the struct has alignment N and padded up to multiple of `N`; contents of the padding are unspecified (though, frequently are zeros); similar to GNU C `__attribute__((aligned(N)))`
- `size[N]`: the struct is padded up to the specified size `N`; contents of the padding are unspecified (though, frequently are zeros)
## Unions
Unions are described as:
```
unionname "[" "\n"
(fieldname type (if[expression])? "\n")+
"]" ("[" attribute* "]")?
```
During fuzzing, syzkaller randomly picks one of the union options.
You may also specify conditions that determine whether the corresponding
option may or may not be selected, depending on values of other fields. See
[the corresponding section](syscall_descriptions_syntax.md#conditional-fields)
for more details.
Unions can have attributes specified in square brackets after the union.
Attributes are:
- `varlen`: union size is the size of the particular chosen option (not statically known); without this attribute unions are statically sized as maximum of all options (similar to C unions)
- `size[N]`: the union is padded up to the specified size `N`; contents of the padding are unspecified (though, frequently are zeros)
## Resources
Resources represent values that need to be passed from output of one syscall to input of another syscall. For example, `close` syscall requires an input value (fd) previously returned by `open` or `pipe` syscall. To achieve this, `fd` is declared as a resource. This is a way of modelling dependencies between syscalls, as defining a syscall as the producer of a resource and another syscall as the consumer defines a loose sense of ordering between them. Resources are described as:
```
"resource" identifier "[" underlying_type "]" [ ":" const ("," const)* ]
```
`underlying_type` is either one of `int8`, `int16`, `int32`, `int64`, `intptr` or another resource (which models inheritance, for example, a socket is a subtype of fd). The optional set of constants represent resource special values, for example, `0xffffffffffffffff` (-1) for "no fd", or `AT_FDCWD` for "the current dir". Special values are used once in a while as resource values. If no special values specified, special value of `0` is used. Resources can then be used as types, for example:
```
resource fd[int32]: 0xffffffffffffffff, AT_FDCWD, 1000000
resource sock[fd]
resource sock_unix[sock]
socket(...) sock
accept(fd sock, ...) sock
listen(fd sock, backlog int32)
```
Resources don't have to be necessarily returned by a syscall. They can be used as any other data type. For example:
```
resource my_resource[int32]
request_producer(..., arg ptr[out, my_resource])
request_consumer(..., arg ptr[inout, test_struct])
test_struct {
...
attr my_resource
}
```
For more complex producer/consumer scenarios, field attributes can be utilized.
For example:
```
resource my_resource_1[int32]
resource my_resource_2[int32]
request_produce1_consume2(..., arg ptr[inout, test_struct])
test_struct {
...
field0 my_resource_1 (out)
field1 my_resource_2 (in)
}
```
Each resource type must be "produced" (used as an output) by at least one syscall
(outside of unions and optional pointers) and "consumed" (used as an input)
by at least one syscall.
## Type Aliases
Complex types that are often repeated can be given short type aliases using the
following syntax:
```
type identifier underlying_type
```
For example:
```
type signalno int32[0:65]
type net_port proc[20000, 4, int16be]
```
Then, type alias can be used instead of the underlying type in any contexts.
Underlying type needs to be described as if it's a struct field, that is,
with the base type if it's required. However, type alias can be used as syscall
arguments as well. Underlying types are currently restricted to integer types,
`ptr`, `ptr64`, `const`, `flags` and `proc` types.
There are some builtin type aliases:
```
type bool8 int8[0:1]
type bool16 int16[0:1]
type bool32 int32[0:1]
type bool64 int64[0:1]
type boolptr intptr[0:1]
type fileoff[BASE] BASE
type filename string[filename]
type buffer[DIR] ptr[DIR, array[int8]]
```
## Type Templates
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
There is builtin type template `optional` defined as:
```
type optional[T] [
val T
void void
] [varlen]
```
## Length
You can specify length of a particular field in struct or a named argument by
using `len`, `bytesize` and `bitsize` types, for example:
```
write(fd fd, buf ptr[in, array[int8]], count len[buf])
sock_fprog {
len len[filter, int16]
filter ptr[in, array[sock_filter]]
}
```
If `len`'s argument is a pointer, then the length of the pointee argument is used.
To denote the length of a field in N-byte words use `bytesizeN`, possible values
for N are 1, 2, 4 and 8.
To denote the length of the parent struct, you can use `len[parent, int8]`.
To denote the length of the higher level parent when structs are embedded into
one another, you can specify the type name of the particular parent:
```
s1 {
f0 len[s2] # length of s2
}
s2 {
f0 s1
f1 array[int32]
f2 len[parent, int32]
}
```
`len` argument can also be a path expression which allows more complex
addressing. Path expressions are similar to C field references, but also allow
referencing parent and sibling elements. A special reference `syscall` used
in the beginning of the path allows to refer directly to the syscall arguments.
For example:
```
s1 {
a ptr[in, s2]
b ptr[in, s3]
c array[int8]
}
s2 {
d array[int8]
}
s3 {
# This refers to the array c in the parent s1.
e len[s1:c, int32]
# This refers to the array d in the sibling s2.
f len[s1:a:d, int32]
# This refers to the array k in the child s4.
g len[i:j, int32]
# This refers to syscall argument l.
h len[syscall:l, int32]
i ptr[in, s4]
}
s4 {
j array[int8]
}
foo(k ptr[in, s1], l ptr[in, array[int8]])
```
## Proc
The `proc` type can be used to denote per process integers.
The idea is to have a separate range of values for each executor, so they don't interfere.
The simplest example is a port number.
The `proc[20000, 4, int16be]` type means that we want to generate an `int16be`
integer starting from `20000` and assign `4` values for each process.
As a result the executor number `n` will get values in the `[20000 + n * 4, 20000 + (n + 1) * 4)` range.
## Integer Constants
Integer constants can be specified as decimal literals, as `0x`-prefixed
hex literals, as `'`-surrounded char literals, or as symbolic constants
extracted from kernel headers or defined by `define` directives. For example:
```
foo(a const[10], b const[-10])
foo(a const[0xabcd])
foo(a int8['a':'z'])
foo(a const[PATH_MAX])
foo(a int32[PATH_MAX])
foo(a ptr[in, array[int8, MY_PATH_MAX]])
define MY_PATH_MAX PATH_MAX + 2
```
## Conditional fields
### In structures
In syzlang, it's possible to specify a condition for every struct field that
determines whether the field should be included or omitted:
```
header_fields {
magic const[0xabcd, int16]
haveInteger int8
} [packed]
packet {
header header_fields
integer int64 (if[value[header:haveInteger] == 0x1])
body array[int8]
} [packed]
some_call(a ptr[in, packet])
```
In this example, the `packet` structure will include the field `integer` only
if `header.haveInteger == 1`. In memory, `packet` will have the following
layout:
| header.magic = 0xabcd | header.haveInteger = 0x1 | integer | body |
| --------------------- | ------------------------ | ------- | ---- |
That corresponds to e.g. the following program:
```
some_call(&AUTO={{AUTO, 0x1}, @value=0xabcd, []})
```
If `header.haveInteger` is not `1`, syzkaller will just pretend that the field
`integer` does not exist.
```
some_call(&AUTO={{AUTO, 0x0}, @void, []})
```
| header.magic = 0xabcd | header.haveInteger = 0x0 | body |
| --------------------- | ------------------------ | ---- |
Every conditional field is assumed to be of variable length and so is the struct
to which this field belongs.
When a variable length field appears in the middle of a structure, the structure
must be marked with `[packed].`
Conditions on bitfields are prohibited:
```
struct {
f0 int
f1 int:3 (if[value[f0] == 0x1]) # It will not compile.
}
```
But you may reference bitfields in your conditions:
```
struct {
f0 int:1
f1 int:7
f2 int (if[value[f0] == value[f1]])
} [packed]
```
### In unions
Let's consider the following example.
```
struct {
type int
body alternatives
}
alternatives [
int int64 (if[value[struct:type] == 0x1])
arr array[int64, 5] (if[value[struct:type] == 0x2])
default int32
] [varlen]
some_call(a ptr[in, struct])
```
In this case, the union option will be selected depending on the value of the
`type` field. For example, if `type` is `0x1`, then it can be either `int` or
`default`:
```
some_call(&AUTO={0x1, @int=0x123})
some_call(&AUTO={0x1, @default=0x123})
```
If `type` is `0x2`, it can be either `arr` or `default`.
If `type` is neither `0x1` nor `0x2`, syzkaller may only select `default`:
```
some_call(&AUTO={0x0, @default=0xabcd})
```
To ensure that a union can always be constructed, the last union field **must always
have no condition**.
Thus, the following definition would fail to compile:
```
alternatives [
int int64 (if[value[struct:type] == 0x1])
arr array[int64, 5] (if[value[struct:type] == 0x1])
] [varlen]
```
During prog mutation and generation syzkaller will select a random union field
whose condition is satisfied.
### Expression syntax
Currently, only `==`, `!=`, `&` and `||` operators are supported. However, the
functionality was designed in such a way that adding more operators is easy.
Feel free to file a GitHub issue or write us an email in case it's needed.
Expressions are evaluated as `int64` values. If the final result of an
expression is not 0, it's assumed to be satisfied.
If you want to reference a field's value, you can do it via
`value[path:to:field]`, which is similar to the `len[]` argument.
```
sub_struct {
f0 int
# Reference a field in a parent struct.
f1 int (if[value[struct:f2]]) # Same as if[value[struct:f2] != 0].
}
struct {
f2 int
f3 sub_struct
f4 int (if[value[f2] == 0x2]) # Reference a sibling field.
f5 int (if[value[f3:f0] == 0x1]) # Reference a nested field.
f6 int (if[value[f3:f0] == 0x1 || value[f3:f0] == 0x2]) # Reference a nested field which either equals to 0x1 or 0x2.
} [packed]
call(a ptr[in, struct])
```
The referenced field must be of integer type and there must be no
conditional fields in the path to it. For example, the following
descriptions will not compile.
```
struct {
f0 int
f1 int (if[value[f0] == 0x1])
f2 int (if[value[f1] == 0x1])
}
```
You may also reference constants in expressions:
```
struct {
f0 int
f1 int
f2 int (if[value[f0] & SOME_CONST == OTHER_CONST])
}
```
## Meta
Description files can also contain `meta` directives that specify meta-information for the whole file.
```
meta noextract
```
Tells `make extract` to not extract constants for this file.
Though, `syz-extract` can still be invoked manually on this file.
```
meta arches["arch1", "arch2"]
```
Restricts this file only to the given set of architectures.
`make extract` and `make generate` will not use it on other architectures.
## Misc
Description files also contain `include` directives that refer to Linux kernel header files,
`incdir` directives that refer to custom Linux kernel header directories
and `define` directives that define symbolic constant values.
The syzkaller executor defines some [pseudo system calls](./pseudo_syscalls.md)
that can be used as any other syscall in a description file. These pseudo
system calls expand to literal C code and can perform user-defined
custom actions. You can find some examples in
[executor/common_linux.h](../executor/common_linux.h).
Also see [tips](syscall_descriptions.md#tips) on writing good descriptions.
===
Don't make assumptions about the kernel source code (it may be different from what you assume it is).
Extensively use the provided code access tools (codesearch-*, git-*, grepper, etc)
to examine the actual source code, and confirm any assumptions.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt:
Bug title: KASAN: slab-use-after-free Read in i2c_adapter_lock_bus
The bug report to reproduce:
==================================================================
BUG: KASAN: slab-use-after-free in i2c_adapter_depth drivers/i2c/i2c-core-base.c:1243 [inline]
BUG: KASAN: slab-use-after-free in i2c_adapter_lock_bus+0x5e/0xf0 drivers/i2c/i2c-core-base.c:849
Read of size 8 at addr ffff8880270b4108 by task syz.4.7872/28255
CPU: 0 UID: 0 PID: 28255 Comm: syz.4.7872 Tainted: G L syzkaller #0 PREEMPT_{RT,(full)}
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/16/2026
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_address_description+0x55/0x1e0 mm/kasan/report.c:378
print_report+0x58/0x70 mm/kasan/report.c:482
kasan_report+0x117/0x150 mm/kasan/report.c:595
i2c_adapter_depth drivers/i2c/i2c-core-base.c:1243 [inline]
i2c_adapter_lock_bus+0x5e/0xf0 drivers/i2c/i2c-core-base.c:849
i2c_lock_bus include/linux/i2c.h:809 [inline]
__i2c_lock_bus_helper drivers/i2c/i2c-core.h:47 [inline]
i2c_smbus_xfer+0xd5/0x310 drivers/i2c/i2c-core-smbus.c:543
i2cdev_ioctl_smbus+0x407/0x700 drivers/i2c/i2c-dev.c:389
i2cdev_ioctl+0x618/0x890 drivers/i2c/i2c-dev.c:478
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f0b2cb8de99
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f0b2ade6028 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f0b2ce15fa0 RCX: 00007f0b2cb8de99
RDX: 0000200000000080 RSI: 0000000000000720 RDI: 0000000000000003
RBP: 00007f0b2cc23eaf R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f0b2ce16038 R14: 00007f0b2ce15fa0 R15: 00007ffe659b19a8
</TASK>
Allocated by task 1326:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
__kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
kasan_kmalloc include/linux/kasan.h:263 [inline]
__do_kmalloc_node mm/slub.c:5334 [inline]
__kmalloc_node_track_caller_noprof+0x57f/0x7c0 mm/slub.c:5471
kmalloc_reserve net/core/skbuff.c:637 [inline]
__alloc_skb+0x2bd/0x7a0 net/core/skbuff.c:715
alloc_skb include/linux/skbuff.h:1384 [inline]
nsim_dev_trap_skb_build drivers/net/netdevsim/dev.c:819 [inline]
nsim_dev_trap_report drivers/net/netdevsim/dev.c:876 [inline]
nsim_dev_trap_report_work+0x2b1/0xcb0 drivers/net/netdevsim/dev.c:922
process_one_work kernel/workqueue.c:3322 [inline]
process_scheduled_works+0xa8e/0x14e0 kernel/workqueue.c:3405
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3486
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
Freed by task 1326:
kasan_save_stack mm/kasan/common.c:57 [inline]
kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
poison_slab_object mm/kasan/common.c:253 [inline]
__kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
kasan_slab_free include/linux/kasan.h:235 [inline]
slab_free_hook mm/slub.c:2677 [inline]
slab_free mm/slub.c:6377 [inline]
kfree+0x1c5/0x6c0 mm/slub.c:6692
skb_kfree_head net/core/skbuff.c:1077 [inline]
skb_free_head net/core/skbuff.c:1089 [inline]
skb_release_data+0x85e/0xab0 net/core/skbuff.c:1116
skb_release_all net/core/skbuff.c:1191 [inline]
__kfree_skb+0x5d/0x210 net/core/skbuff.c:1205
nsim_dev_trap_report drivers/net/netdevsim/dev.c:892 [inline]
nsim_dev_trap_report_work+0x879/0xcb0 drivers/net/netdevsim/dev.c:922
process_one_work kernel/workqueue.c:3322 [inline]
process_scheduled_works+0xa8e/0x14e0 kernel/workqueue.c:3405
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3486
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
The buggy address belongs to the object at ffff8880270b4000
which belongs to the cache kmalloc-4k of size 4096
The buggy address is located 264 bytes inside of
freed 4096-byte region [ffff8880270b4000, ffff8880270b5000)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x270b0
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0x80000000000040(head|node=0|zone=1)
page_type: f5(slab)
raw: 0080000000000040 ffff88813ffb2140 dead000000000100 dead000000000122
raw: 0000000000000000 0000000800040004 00000000f5000000 0000000000000000
head: 0080000000000040 ffff88813ffb2140 dead000000000100 dead000000000122
head: 0000000000000000 0000000800040004 00000000f5000000 0000000000000000
head: 0080000000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
head: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 1, tgid 1 (swapper/0), ts 13082770889, free_ts 13069657874
set_page_owner include/linux/page_owner.h:32 [inline]
post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1859
prep_new_page mm/page_alloc.c:1867 [inline]
get_page_from_freelist+0x262a/0x26a0 mm/page_alloc.c:3946
__alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5304
alloc_slab_page mm/slub.c:3266 [inline]
allocate_slab+0x79/0x5e0 mm/slub.c:3380
new_slab mm/slub.c:3426 [inline]
refill_objects+0x2d8/0x350 mm/slub.c:7310
refill_sheaf mm/slub.c:2804 [inline]
__pcs_replace_empty_main+0x330/0x690 mm/slub.c:4675
alloc_from_pcs mm/slub.c:4773 [inline]
slab_alloc_node mm/slub.c:4905 [inline]
__kmalloc_cache_noprof+0x468/0x6b0 mm/slub.c:5485
_kmalloc_noprof include/linux/slab.h:988 [inline]
_kzalloc_noprof include/linux/slab.h:1309 [inline]
kobject_uevent_env+0x28c/0x9e0 lib/kobject_uevent.c:543
device_add+0x544/0xb80 drivers/base/core.c:3738
device_create_groups_vargs drivers/base/core.c:4454 [inline]
device_create+0x269/0x300 drivers/base/core.c:4493
mon_bin_add+0xb6/0x130 drivers/usb/mon/mon_bin.c:1371
mon_bus_init+0x173/0x2b0 drivers/usb/mon/mon_main.c:291
mon_bus_add drivers/usb/mon/mon_main.c:188 [inline]
mon_notify+0x10c/0x3f0 drivers/usb/mon/mon_main.c:219
notifier_call_chain+0x1a5/0x3d0 kernel/notifier.c:85
blocking_notifier_call_chain+0x6a/0x90 kernel/notifier.c:380
usb_register_bus+0xcf/0x150 drivers/usb/core/hcd.c:904
page last free pid 10 tgid 10 stack trace:
reset_page_owner include/linux/page_owner.h:25 [inline]
__free_pages_prepare mm/page_alloc.c:1406 [inline]
free_pages_prepare+0x946/0xa40 mm/page_alloc.c:1451
__free_contig_range_common+0x174/0x340 mm/page_alloc.c:6897
__free_contig_range mm/page_alloc.c:6942 [inline]
free_pages_bulk+0x48/0x120 mm/page_alloc.c:5257
vm_area_free_pages mm/vmalloc.c:3439 [inline]
vfree+0x26f/0x510 mm/vmalloc.c:3488
delayed_vfree_work+0x55/0x80 mm/vmalloc.c:3392
process_one_work kernel/workqueue.c:3322 [inline]
process_scheduled_works+0xa8e/0x14e0 kernel/workqueue.c:3405
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3486
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
Memory state around the buggy address:
ffff8880270b4000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8880270b4080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff8880270b4100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff8880270b4180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8880270b4200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
The list of existing description files:
acpi_thermal_rel.txt
aio.txt
auto.txt
binfmt.txt
bpf.txt
bpf_prog.txt
bpf_trace.txt
cgroup.txt
damon.txt
dev_ashmem.txt
dev_bifrost.txt
dev_binder.txt
dev_binderfs.txt
dev_block.txt
dev_bsg.txt
dev_bus_usb.txt
dev_camx.txt
dev_cdrom.txt
dev_cec.txt
dev_char_usb.txt
dev_comedi.txt
dev_dma_heap.txt
dev_dri.txt
dev_dsp.txt
dev_dvb_demux.txt
dev_dvb_dvr.txt
dev_dvb_frontend.txt
dev_fb.txt
dev_floppy.txt
dev_hidraw.txt
dev_i2c.txt
dev_i915.txt
dev_img_rogue.txt
dev_infiniband_rdma.txt
dev_infiniband_rdma_cm.txt
dev_input.txt
dev_iommu.txt
dev_kvm.txt
dev_kvm_amd64.txt
dev_kvm_arm64.txt
dev_kvm_extra.txt
dev_kvm_riscv64.txt
dev_loop.txt
dev_mali.txt
dev_media.txt
dev_msm.txt
dev_msr.txt
dev_mtd.txt
dev_nbd.txt
dev_net_tun.txt
dev_panthor.txt
dev_ppp.txt
dev_ptmx.txt
dev_ptp.txt
dev_qat_adf_ctl.txt
dev_qrtr_tun.txt
dev_random.txt
dev_rfkill.txt
dev_rtc.txt
dev_sequencer.txt
dev_sg.txt
dev_snapshot.txt
dev_snd_control.txt
dev_snd_hw.txt
dev_snd_midi.txt
dev_snd_pcm.txt
dev_snd_seq.txt
dev_snd_timer.txt
dev_sr.txt
dev_sw_sync.txt
dev_tee.txt
dev_tlk_device.txt
dev_trusty.txt
dev_udmabuf.txt
dev_uhid.txt
dev_uinput.txt
dev_usb_hiddev.txt
dev_usbmon.txt
dev_userio.txt
dev_vfio.txt
dev_vga_arbiter.txt
dev_vhci.txt
dev_video4linux.txt
dev_video4linux_vim2m.txt
dev_virtual_nci.txt
dev_vtpm.txt
fanotify.txt
filesystem.txt
fs_9p.txt
fs_fuse.txt
fs_incfs.txt
fs_ioctl.txt
fs_ioctl_autofs.txt
fs_ioctl_btrfs.txt
fs_ioctl_ext4.txt
fs_ioctl_f2fs.txt
fs_ioctl_fat.txt
fs_ioctl_fscrypt.txt
fs_ioctl_fsverity.txt
fs_ioctl_nilfs2.txt
fs_ioctl_ocfs2.txt
fs_ioctl_xfs.txt
futex.txt
hafnium.txt
inotify.txt
io_uring.txt
ipc.txt
key.txt
kfuzztest.txt
l2cap.txt
landlock.txt
lsm.txt
namespaces.txt
net_80211.txt
netfilter.txt
netfilter_arp.txt
netfilter_bridge.txt
netfilter_ipv4.txt
netfilter_ipv6.txt
netfilter_ipvs.txt
netfilter_targets.txt
pagemap_ioctl.txt
perf.txt
prctl.txt
quotactl.txt
seccomp.txt
security_apparmor.txt
security_selinux.txt
security_smack.txt
socket.txt
socket_alg.txt
socket_ax25.txt
socket_bluetooth.txt
socket_bluetooth_defs_default.txt
socket_bluetooth_defs_mips.txt
socket_caif.txt
socket_can.txt
socket_ieee802154.txt
socket_inet.txt
socket_inet6.txt
socket_inet_dccp.txt
socket_inet_icmp.txt
socket_inet_igmp.txt
socket_inet_l2tp.txt
socket_inet_sctp.txt
socket_inet_tcp.txt
socket_inet_udp.txt
socket_ip_tunnel.txt
socket_isdn.txt
socket_isdn_defs_386_arm.txt
socket_isdn_defs_cmd_default.txt
socket_isdn_defs_common_default.txt
socket_isdn_defs_mips.txt
socket_kcm.txt
socket_key.txt
socket_llc.txt
socket_netlink.txt
socket_netlink_audit.txt
socket_netlink_crypto.txt
socket_netlink_generic.txt
socket_netlink_generic_80211.txt
socket_netlink_generic_batadv.txt
socket_netlink_generic_devlink.txt
socket_netlink_generic_ethtool.txt
socket_netlink_generic_fou.txt
socket_netlink_generic_gtp.txt
socket_netlink_generic_mptcp.txt
socket_netlink_generic_net_dm.txt
socket_netlink_generic_netlabel.txt
socket_netlink_generic_nfc.txt
socket_netlink_generic_seg6.txt
socket_netlink_generic_smc.txt
socket_netlink_generic_team.txt
socket_netlink_generic_wireguard.txt
socket_netlink_netfilter.txt
socket_netlink_netfilter_acct.txt
socket_netlink_netfilter_conntrack.txt
socket_netlink_netfilter_conntrack_exp.txt
socket_netlink_netfilter_conntrack_helper.txt
socket_netlink_netfilter_ipset.txt
socket_netlink_netfilter_log.txt
socket_netlink_netfilter_nft_compat.txt
socket_netlink_netfilter_nftables.txt
socket_netlink_netfilter_osf.txt
socket_netlink_netfilter_queue.txt
socket_netlink_netfilter_timeout.txt
socket_netlink_rdma.txt
socket_netlink_route.txt
socket_netlink_route_sched.txt
socket_netlink_route_sched_retired.txt
socket_netlink_sock_diag.txt
socket_netlink_xfrm.txt
socket_netrom.txt
socket_nfc.txt
socket_nvme_of_tcp.txt
socket_packet.txt
socket_phonet.txt
socket_pppox.txt
socket_pppox_defs_386_arm.txt
socket_pppox_defs_default.txt
socket_pppox_defs_mips.txt
socket_qipcrtr.txt
socket_rds.txt
socket_rose.txt
socket_rxrpc.txt
socket_tipc.txt
socket_tipc_netlink.txt
socket_unix.txt
socket_vnet.txt
socket_x25.txt
socket_xdp.txt
sys.txt
ublk.txt
uffd.txt
usbip.txt
vmw_vmci.txt
vnet.txt
vnet_mptcp.txt
vusb.txt
watch_queue.txt
xattr.txt
|
| 5/2 |
2026/07/30 12:17 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 18818
output: 24
thoughts: 1397
Thoughts: **KASAN Slab-Use-After-Free Deep Dive**
Okay, so I've got a KASAN slab-use-after-free in `i2c_adapter_lock_bus`. The crash occurs at `drivers/i2c/i2c-core-base.c:849`. The stack trace shows the call path: `i2c_adapter_lock_bus` -> `i2c_smbus_xfer` -> `i2cdev_ioctl_smbus` -> `i2cdev_ioctl`. It looks like it's on something related to an `i2c_adapter` or `i2c_client`.
The initial allocation happens within `nsim_dev_trap_report_work` in `netdevsim`. Huh, that's interesting. Then I see the freed object is actually an `sk_buff` of size 4096 bytes. The buggy address is 264 bytes into this 4096-byte region, so it's a memory region within the buffer. Now, wait a minute... an `skb` is 4096 bytes, but the kernel uses the `kmalloc-4k` cache, right? The `skb->head` is what's allocated from `kmalloc-4k`.
But how could an `i2c_adapter` end up inside `skb->head`? Could it be that the `i2c_adapter` was allocated in the `kmalloc-4k` region, freed, and *then* that same region was re-allocated as `skb->head` and subsequently freed again? That's the most likely scenario given the KASAN report, which doesn't explicitly show the `i2c_adapter` allocation.
Let's look at the free stack trace now. It's freed as `skb->head`, via `skb_release_data`, `__kfree_skb`, and finally back to `nsim_dev_trap_report_work`. Okay, that confirms that the problematic memory region was associated with the `sk_buff` when the UAF happened.
The page itself was last allocated by `kobject_uevent_env` via `usb_register_bus` β no that is not correct. The relevant allocation is hidden by `skb->head` allocations.
So, let's now investigate the `i2cdev_ioctl_smbus` and `i2c_smbus_xfer` functions. In `i2cdev_ioctl_smbus`, it uses `client->adapter`. Where does `client` come from? It's `file->private_data` in `i2cdev_ioctl`. That means that the `file->private_data` must be an `i2c_client`. Ah, right, when you open `/dev/i2c-X`, the kernel creates an `i2c_client` and assigns it to `file->private_data`. So, the `i2c_client` must be allocated during the `i2cdev_open` call. Now to review `drivers/i2c/i2c-dev.c` in detail to determine the memory management.
|
| 6/2 |
2026/07/30 12:18 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 598: static int i2cdev_open(struct inode *inode, struct file *file)
599: {
600: unsigned int minor = iminor(inode);
601: struct i2c_client *client;
602: struct i2c_adapter *adap;
603:
604: adap = i2c_get_adapter(minor);
605: if (!adap)
606: return -ENODEV;
607:
608: /* This creates an anonymous i2c_client, which may later be
609: * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
610: *
611: * This client is ** NEVER REGISTERED ** with the driver model
612: * or I2C core code!! It just holds private copies of addressing
613: * information and maybe a PEC flag.
614: */
615: client = kzalloc_obj(*client);
616: if (!client) {
617: i2c_put_adapter(adap);
618: return -ENOMEM;
619: }
620: snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
621:
622: client->adapter = adap;
623: file->private_data = client;
624:
625: return 0;
626: }
SourceFile:drivers/i2c/i2c-dev.c]
|
| 7/2 |
2026/07/30 12:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 21409
output: 25
thoughts: 59
Thoughts: **Dissecting the I2C Adapter Retrieval**
Okay, so I'm looking at this code and trying to trace how the I2C adapter is being accessed. My initial impression is that the `client->adapter` is going to be assigned the variable `adap`. That looks like it comes from calling `i2c_get_adapter(minor)`. That means I'm going to want to check that method out.
It's clear that `i2c_get_adapter` is the crucial piece here, and that it is taking a `minor` argument. Importantly, it's also taking a reference to the adapter, whatever that turns out to mean in practice. Time to dive into the implementation of `i2c_get_adapter` and see how it works!
|
| 8/2 |
2026/07/30 12:18 |
tool |
codesearch-definition-source |
0m
Args: map[Name:i2c_get_adapter]
Results: map[SourceCode:2628: struct i2c_adapter *i2c_get_adapter(int nr)
2629: {
2630: struct i2c_adapter *adapter;
2631:
2632: mutex_lock(&core_lock);
2633: adapter = idr_find(&i2c_adapter_idr, nr);
2634: if (!adapter)
2635: goto exit;
2636:
2637: if (try_module_get(adapter->owner))
2638: get_device(&adapter->dev);
2639: else
2640: adapter = NULL;
2641:
2642: exit:
2643: mutex_unlock(&core_lock);
2644: return adapter;
2645: }
SourceFile:drivers/i2c/i2c-core-base.c]
|
| 9/2 |
2026/07/30 12:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 21924
output: 24
thoughts: 39
Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective:
**Diving into the I2C Adapter Lifecycle**
Right, so I'm tracing the flow of events when an I2C device is handled, and I'm focusing on the adapter itself. First, I see `i2c_get_adapter` being called, which then immediately calls `get_device(&adapter->dev)`. I know that `get_device` is the foundational function for device registration in the kernel. So, I'm thinking about the implications of that adapter device struct, and how this initial call sets the stage for future operations. Then, when the file representing that I2C device is closed, that's when `i2cdev_release` gets called. Now, I'm thinking about the resource management implications here and how the closing of the device file signals the kernel that the resources associated with it are no longer needed, and this function handles the necessary cleanup process, including releasing any hold on the adapter resources. I'm imagining how that's all tied together with the broader framework of device discovery, resource allocation, and, importantly, the kernel's way of gracefully handling the life cycle of the I2C bus.
|
| 10/2 |
2026/07/30 12:18 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 628: static int i2cdev_release(struct inode *inode, struct file *file)
629: {
630: struct i2c_client *client = file->private_data;
631:
632: i2c_put_adapter(client->adapter);
633: kfree(client);
634: file->private_data = NULL;
635:
636: return 0;
637: }
SourceFile:drivers/i2c/i2c-dev.c]
|
| 11/2 |
2026/07/30 12:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 22422
output: 23
thoughts: 255
Thoughts: **Debugging an I2C Adapter Release**
Okay, so `i2c_put_adapter` calls `put_device` on the adapter's device. That seems standard. But here's the kicker: if the adapter is freed while a file is still open, that implies `get_device` somehow *failed* to prevent the adapter from being released prematurely. That makes no sense. Hold on... `get_device` is supposed to increment the reference count of `adapter->dev`, right? So the adapter shouldn't be released until that count hits zero. If the adapter *is* freed, then its reference count must have dropped to zero. But `i2cdev_open` increments the count, so that *shouldn't* happen.
Alright, so this points to a few possibilities: either someone called `put_device` too many times and decremented it below zero β which is really bad and should have been caught β or, the adapter is being freed without properly waiting for its `adapter->dev` reference count to actually reach zero.
Let's dig deeper. How are these `i2c_adapter` structures allocated and freed in the first place? Usually, it's either embedded within another struct, or it's dynamically allocated. If it's embedded, and that containing struct is freed *without* waiting for the `adapter->dev` refcount to be zero, that's a classic memory management bug right there.
Wait a second, the KASAN report specifies an address, 264 bytes into a 4096-byte region, that's a really useful clue. Let's see how that relates to the size of the `i2c_adapter` struct; that should tell me more about how this is being allocated.
|
| 12/2 |
2026/07/30 12:18 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:owner OffsetBits:0 SizeBits:64] map[Name:class OffsetBits:64 SizeBits:32] map[Name:algo OffsetBits:128 SizeBits:64] map[Name:algo_data OffsetBits:192 SizeBits:64] map[Name:lock_ops OffsetBits:256 SizeBits:64] map[Name:bus_lock OffsetBits:320 SizeBits:1024] map[Name:mux_lock OffsetBits:1344 SizeBits:1024] map[Name:timeout OffsetBits:2368 SizeBits:32] map[Name:retries OffsetBits:2400 SizeBits:32] map[Name:dev OffsetBits:2432 SizeBits:11776] map[Name:locked_flags OffsetBits:14208 SizeBits:64] map[Name:nr OffsetBits:14272 SizeBits:32] map[Name:name OffsetBits:14304 SizeBits:384] map[Name:dev_released OffsetBits:14720 SizeBits:704] map[Name:userspace_clients_lock OffsetBits:15424 SizeBits:1024] map[Name:userspace_clients OffsetBits:16448 SizeBits:128] map[Name:bus_recovery_info OffsetBits:16576 SizeBits:64] map[Name:quirks OffsetBits:16640 SizeBits:64] map[Name:host_notify_domain OffsetBits:16704 SizeBits:64] map[Name:bus_regulator OffsetBits:16768 SizeBits:64] map[Name:debugfs OffsetBits:16832 SizeBits:64] map[Name:addrs_in_instantiation OffsetBits:16896 SizeBits:128]]]
|
| 13/2 |
2026/07/30 12:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 23590
output: 27
thoughts: 189
Thoughts: **Analyzing a KASAN Report and I2C Bus Locking**
Okay, the KASAN report is screaming about a read of size 8 at address `ffff8880270b4108`. The system says this buggy address is 264 bytes into a freed 4096-byte region. 264 bytes is 2112 bits, that makes sense. Let's see... the report mentions `bus_lock`. I know from experience that the `bus_lock` is at offset 320 bits (40 bytes), or is it? Let me confirm that again, 40 bytes.
The `i2c_adapter_lock_bus` function is accessing `adapter->bus_lock`. Ah, right, that function calls `rt_mutex_lock(&adapter->bus_lock)`. That makes sense. Wait, I remember `bus_lock` is a `struct rt_mutex`.
Okay, I need to get the source code for `i2c_adapter_lock_bus` to understand how that mutex is being used within the I2C bus locking mechanism. Let's dig in and see what's going on there.
|
| 14/2 |
2026/07/30 12:18 |
tool |
codesearch-definition-source |
0m
Args: map[Name:i2c_adapter_lock_bus]
Results: map[SourceCode: 840: /**
841: * i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
842: * @adapter: Target I2C bus segment
843: * @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT
844: * locks only this branch in the adapter tree
845: */
846: static void i2c_adapter_lock_bus(struct i2c_adapter *adapter,
847: unsigned int flags)
848: {
849: rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter));
850: }
SourceFile:drivers/i2c/i2c-core-base.c]
|
| 15/2 |
2026/07/30 12:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 24305
output: 25
thoughts: 17
Thoughts: Here's my thought process, as if I were the one thinking it:
**Digging into that `i2c_adapter_depth` Function...**
Okay, so I'm looking at this `i2c_adapter_depth` function, and something just clicked. I see it's trying to figure out the nesting depth of an I2C adapter. But hold on a second... it's also directly accessing the `adapter` itself within the function. I initially glazed over it, but that's a key detail I almost missed. I need to keep that relationship in mind as I keep going.
|
| 16/2 |
2026/07/30 12:18 |
tool |
codesearch-definition-source |
0m
Args: map[Name:i2c_adapter_depth]
Results: map[SourceCode:1237: unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
1238: {
1239: unsigned int depth = 0;
1240: struct device *parent;
1241:
1242: for (parent = adapter->dev.parent; parent; parent = parent->parent)
1243: if (parent->type == &i2c_adapter_type)
1244: depth++;
1245:
1246: WARN_ONCE(depth >= MAX_LOCKDEP_SUBCLASSES,
1247: "adapter depth exceeds lockdep subclass limit\n");
1248:
1249: return depth;
1250: }
SourceFile:drivers/i2c/i2c-core-base.c]
|
| 17/2 |
2026/07/30 12:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 24712
output: 19
thoughts: 72
Thoughts: **Dissecting the Memory Layout**
Okay, so I'm tracing through this code and I see an access to `adapter->dev.parent`. Right, `adapter->dev.parent` is the thing that triggered the alert. Let's see... `adapter->dev` is accessed. I need to figure out the offset of `dev` within the `adapter` structure. Let me see... 2432 bits equals 304 bytes. Okay, so `dev` is 304 bytes into the `adapter` structure. Since the issue is at `adapter->dev.parent`, I am now sure the offset of `dev` is actually at 304 bytes into the `adapter` struct. Excellent, `parent` is a field *within* the `struct device`. Now, I need to understand the layout of `struct device` to properly diagnose this. I am going to examine the `struct device` definition right away. Let's check the `struct device` layout to see what `parent` is.
|
| 18/2 |
2026/07/30 12:18 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:kobj OffsetBits:0 SizeBits:512] map[Name:parent OffsetBits:512 SizeBits:64] map[Name:p OffsetBits:576 SizeBits:64] map[Name:init_name OffsetBits:640 SizeBits:64] map[Name:type OffsetBits:704 SizeBits:64] map[Name:bus OffsetBits:768 SizeBits:64] map[Name:driver OffsetBits:832 SizeBits:64] map[Name:platform_data OffsetBits:896 SizeBits:64] map[Name:driver_data OffsetBits:960 SizeBits:64] map[Name:driver_override OffsetBits:1024 SizeBits:1088] map[Name:mutex OffsetBits:2112 SizeBits:1024] map[Name:links OffsetBits:3136 SizeBits:448] map[Name:power OffsetBits:3584 SizeBits:5440] map[Name:pm_domain OffsetBits:9024 SizeBits:64] map[Name:msi OffsetBits:9088 SizeBits:128] map[Name:dma_mask OffsetBits:9216 SizeBits:64] map[Name:coherent_dma_mask OffsetBits:9280 SizeBits:64] map[Name:bus_dma_limit OffsetBits:9344 SizeBits:64] map[Name:dma_range_map OffsetBits:9408 SizeBits:64] map[Name:dma_parms OffsetBits:9472 SizeBits:64] map[Name:dma_pools OffsetBits:9536 SizeBits:128] map[Name:dma_mem OffsetBits:9664 SizeBits:64] map[Name:cma_area OffsetBits:9728 SizeBits:64] map[Name:dma_io_tlb_mem OffsetBits:9792 SizeBits:64] map[Name:archdata OffsetBits:9856 SizeBits:0] map[Name:of_node OffsetBits:9856 SizeBits:64] map[Name:fwnode OffsetBits:9920 SizeBits:64] map[Name:numa_node OffsetBits:9984 SizeBits:32] map[Name:devt OffsetBits:10016 SizeBits:32] map[Name:id OffsetBits:10048 SizeBits:32] map[Name:devres_lock OffsetBits:10112 SizeBits:1024] map[Name:devres_head OffsetBits:11136 SizeBits:128] map[Name:class OffsetBits:11264 SizeBits:64] map[Name:groups OffsetBits:11328 SizeBits:64] map[Name:release OffsetBits:11392 SizeBits:64] map[Name:iommu_group OffsetBits:11456 SizeBits:64] map[Name:iommu OffsetBits:11520 SizeBits:64] map[Name:physical_location OffsetBits:11584 SizeBits:64] map[Name:removable OffsetBits:11648 SizeBits:32] map[Name:flags OffsetBits:11712 SizeBits:64]]]
|
| 19/2 |
2026/07/30 12:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 25925
output: 21
thoughts: 690
Thoughts: **Debugging a KASAN Report: Unraveling the Memory Access**
Okay, so I'm digging into this KASAN report, and it looks like we have a problem with memory access in an `i2c_adapter`. The report is pointing to a read of size 8 at a specific address, and it's flagged as being inside a freed region. The buggy address is at a 264-byte offset within that region.
My initial thought was to find the `parent` pointer of the `device` struct, which resides inside the `i2c_adapter`. I figured it would be an offset of 64 bytes inside of the `device` struct. Thus, the offset of `adapter->dev.parent` is 304 + 64 = 368 bytes inside the `i2c_adapter`. But, the buggy address is at 264 bytes into the region!
I re-checked the `i2c_adapter` layout, double-checking the offset of `dev`, which is at 304 bytes. Then it hit me: 264 bytes is 2112 bits, which is more directly useful to look at with regards to the bitfield layout of the structure! So what's at 2112 bits within the `i2c_adapter`?
I started tracing down the structure's layout again. `mux_lock` is at 1344 bits with a size of 1024 bits. So it ends at 2368 bits. Wait, 2112 bits is inside the `mux_lock`? No, no, `mux_lock` is a `struct rt_mutex`.
Okay, the `bus_lock` is at 320 bits with a size of 1024 bits. It ends at 1344 bits. And here's where it clicks β `i2c_adapter_lock_bus` calls `rt_mutex_lock_nested` on `adapter->bus_lock`.
I recall that `bus_lock` is at offset 40 bytes (320 bits). If the buggy address is 264 bytes, that's 264 - 40 = 224 bytes inside the `bus_lock` memory region, which is the `rt_mutex`!
Wait, I need to know the size of `rt_mutex`. It's 1024 bits = 128 bytes. So `bus_lock` would end at 40 + 128 = 168 bytes. So I am still looking past the `bus_lock` structure. What IS at 264 bytes?
Let's look at `i2c_adapter_depth` again, because it accesses `adapter->dev.parent`.
The KASAN report says it's a read of size 8 at address `ffff8880270b4108`. The buggy address is located 264 bytes inside of the freed region [ffff8880270b4000, ffff8880270b5000). So, 0x108 = 264 bytes.
So, if `adapter` is at `ffff8880270b4000`, `adapter->dev.parent` should be at `ffff8880270b4170` (304 + 64). But the buggy address is `ffff8880270b4108`. I'm off by 104 bytes in my calculations. What's at 264 bytes (0x108) again?
I'm getting closer, let's go back and check the layout of `struct rt_mutex` again. I need to understand what's actually located at this offset.
|
| 20/2 |
2026/07/30 12:18 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:rtmutex OffsetBits:0 SizeBits:704] map[Name:dep_map OffsetBits:704 SizeBits:320]]]
|
| 21/2 |
2026/07/30 12:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 27552
output: 31
thoughts: 434
Thoughts: **Analyzing a KASAN Report and Memory Offsets**
Okay, let's break this down. First, I'm noting that the `struct rt_mutex` definition has its `dep_map` member starting at an offset of 88 bytes. I also know that `bus_lock` is at offset 40 bytes. This means `bus_lock.dep_map` should start at 40 + 88 = 128 bytes. The real question is, what's at 264 bytes? I need to check the `i2c_adapter` structure again. Let me quickly refresh my memory of the layout; `lock_ops` is at 32 bytes, `bus_lock` at 40 bytes, `mux_lock` at 168 bytes, and `timeout` is at 296 bytes. So 264 bytes falls within `mux_lock`, specifically!
But wait, I need to be more precise. If `mux_lock` is at 168 bytes, then `mux_lock.dep_map` should be at 168 + 88 = 256 bytes. And `mux_lock.dep_map` takes up 40 bytes. So 264 bytes *is* inside `mux_lock.dep_map`. This is where it gets interesting: why would `i2c_adapter_lock_bus` be accessing `mux_lock.dep_map`? Ah, I remember, the call to `rt_mutex_lock_nested` passes `&adapter->bus_lock`.
Ok, `bus_lock` is at 40 bytes. But here's the kicker: the KASAN report is screaming about a read of size 8 at `ffff8880270b4108`. That address looks familiar! Let me compute the offset. `ffff8880270b4108` is `ffff8880270b4000` + 0x108. And 0x108 is, yes, 264 in decimal. So that matches the offset I was trying to find, it is accessing `mux_lock.dep_map`. I need to now check the `rt_mutex_lock_nested` macro to understand this better.
|
| 22/2 |
2026/07/30 12:18 |
tool |
codesearch-find-references |
0m
Args: map[IncludeSnippetLines:5 Name:rt_mutex_lock_nested]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:i2c_adapter_lock_bus SourceFile:drivers/i2c/i2c-core-base.c SourceLine:849 SourceSnippet: 844: * locks only this branch in the adapter tree
845: */
846: static void i2c_adapter_lock_bus(struct i2c_adapter *adapter,
847: unsigned int flags)
848: {
849: rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter));
850: }
] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:i2c_mux_lock_bus SourceFile:drivers/i2c/i2c-mux.c SourceLine:135 SourceSnippet: 130: static void i2c_mux_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
131: {
132: struct i2c_mux_priv *priv = adapter->algo_data;
133: struct i2c_adapter *parent = priv->muxc->parent;
134:
135: rt_mutex_lock_nested(&parent->mux_lock, i2c_adapter_depth(adapter));
136: if (!(flags & I2C_LOCK_ROOT_ADAPTER))
137: return;
138: i2c_lock_bus(parent, flags);
139: }
] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:i2c_parent_lock_bus SourceFile:drivers/i2c/i2c-mux.c SourceLine:172 SourceSnippet: 167: unsigned int flags)
168: {
169: struct i2c_mux_priv *priv = adapter->algo_data;
170: struct i2c_adapter *parent = priv->muxc->parent;
171:
172: rt_mutex_lock_nested(&parent->mux_lock, i2c_adapter_depth(adapter));
173: i2c_lock_bus(parent, flags);
174: }
] map[ReferenceKind:takes-address-of ReferencingEntityKind:global_variable ReferencingEntityName:__UNIQUE_ID_addressable_rt_mutex_lock_nested_817 SourceFile:kernel/locking/rtmutex_api.c SourceLine:80 SourceSnippet: 80: EXPORT_SYMBOL_GPL(rt_mutex_lock_nested);
] map[ReferenceKind:takes-address-of ReferencingEntityKind:global_variable ReferencingEntityName:__gendwarfksyms_ptr_rt_mutex_lock_nested SourceFile:kernel/locking/rtmutex_api.c SourceLine:80 SourceSnippet: 80: EXPORT_SYMBOL_GPL(rt_mutex_lock_nested);
] map[ReferenceKind:takes-address-of ReferencingEntityKind:global_variable ReferencingEntityName:__gendwarfksyms_ptr_rt_mutex_lock_nested SourceFile:kernel/locking/rtmutex_api.c SourceLine:80 SourceSnippet: 80: EXPORT_SYMBOL_GPL(rt_mutex_lock_nested);
]] TruncatedOutput:false]
|
| 23/2 |
2026/07/30 12:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 29461
output: 23
thoughts: 873
Thoughts: **Debugging a KASAN Report: Unraveling a Use-After-Free in i2c_adapter_depth**
Okay, first things first, `rt_mutex_lock_nested` isn't a macro, it's an exported function, so that's not the issue. Let's get back to `i2c_adapter_depth` and refresh my memory. Right, it's about checking the nesting depth of i2c adapters, pretty straightforward.
Now, let's look closely at the crash reported by KASAN, and the code line where it's happening, which is `i2c_adapter_depth` at `drivers/i2c/i2c-core-base.c:1243`. Line 1243 is the conditional check `if (parent->type == &i2c_adapter_type)`. Wait a minute, what is the type of `parent`? Oh right, it's `struct device *`.
Now, if I remember correctly, `adapter->dev.parent` is at offset 304 + 64 = 368 bytes. The KASAN report is referencing line 1243 which accesses `parent->type`. I know the type member is at offset 88 bytes within `struct device`. I need to track down the address that's causing the access violation, this should be fun.
The report says the crash is at `i2c_adapter_depth` reading `parent->type`, so the crash address is an offset to `parent`. The KASAN report states that we have `ffff8880270b4000` + 0x108 - 88 = `ffff8880270b4000` + 176 = `ffff8880270b40b0`. So, if `parent` is this address, then `parent->type` will be at `ffff8880270b40b0` + 88 = `ffff8880270b4108`. And there it is, the address `ffff8880270b4108`! The report is correct!
So, the faulty `parent` pointer is `ffff8880270b40b0`. The pointer is pointing inside a freed 4096-byte region, [ffff8880270b4000, ffff8880270b5000), which is a clear sign of use-after-free. If `parent` points inside the freed region, then its `struct device` instance was freed.
Since `parent` is `adapter->dev.parent`, it seems the parent device was freed. So, the `parent` device is at `ffff8880270b40b0` within `[ffff8880270b4000, ffff8880270b5000)`. Wait, could `ffff8880270b40b0` be the start of an i2c adapter, and not a `struct device`? Well, the dev member is at offset 304 in the i2c adapter. Let's see, if this were an `i2c_adapter` then the `parent` device would be at offset 304 bytes. Then it would be `ffff8880270b4000` + 304 = `ffff8880270b4130`. But the crash is happening on `ffff8880270b40b0`.
Okay, so we know `ffff8880270b40b0` is `ffff8880270b4000` + 176. Now, what's at offset 176? The struct layout is where the money is at... Is it a `struct i2c_client`? Looks like we have some homework.
|
| 24/2 |
2026/07/30 12:19 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:flags OffsetBits:0 SizeBits:16] map[Name:addr OffsetBits:16 SizeBits:16] map[Name:name OffsetBits:32 SizeBits:160] map[Name:adapter OffsetBits:192 SizeBits:64] map[Name:dev OffsetBits:256 SizeBits:11776] map[Name:init_irq OffsetBits:12032 SizeBits:32] map[Name:irq OffsetBits:12064 SizeBits:32] map[Name:detected OffsetBits:12096 SizeBits:128] map[Name:slave_cb OffsetBits:12224 SizeBits:64] map[Name:devres_group_id OffsetBits:12288 SizeBits:64] map[Name:debugfs OffsetBits:12352 SizeBits:64]]]
|
| 25/2 |
2026/07/30 12:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 31511
output: 21
thoughts: 365
Thoughts: **Deconstructing the KASAN Report**
Okay, let's break this down. From the initial clues, it looked like `i2c_client->dev` was the key. We figured that if the `parent` pointer was equal to that device, then we could calculate the address of `i2c_client`. However, that assumption seems wrong.
The KASAN report clarifies things considerably. It tells us the problematic memory address lies within a 4K object located at `ffff8880270b4000`. The error is happening 264 bytes into this object, at address `ffff8880270b4108`. We know the code is accessing `parent->type`, and `type` is at offset 88 in `struct device`. This is useful. This tells us `parent` must be at `ffff8880270b4108 - 88 = ffff8880270b40b0`, which is 176 bytes into this freed 4KB region. The bug is caused by accessing an invalid `parent` pointer and dereferencing the `type` field, which we know is at offset 88 in `struct device`, so `parent` must be the start of `struct device`. So, we're looking for a structure that contains a `struct device` at offset 176. Time to start checking likely suspects of size 4096. My immediate thought is `struct usb_interface`. Let's see if that's the culprit.
|
| 26/2 |
2026/07/30 12:19 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:altsetting OffsetBits:0 SizeBits:64] map[Name:cur_altsetting OffsetBits:64 SizeBits:64] map[Name:num_altsetting OffsetBits:128 SizeBits:32] map[Name:intf_assoc OffsetBits:192 SizeBits:64] map[Name:minor OffsetBits:256 SizeBits:32] map[Name:condition OffsetBits:288 SizeBits:32] map[Name:sysfs_files_created OffsetBits:320 SizeBits:1] map[Name:ep_devs_created OffsetBits:321 SizeBits:1] map[Name:unregistering OffsetBits:322 SizeBits:1] map[Name:needs_remote_wakeup OffsetBits:323 SizeBits:1] map[Name:needs_altsetting0 OffsetBits:324 SizeBits:1] map[Name:needs_binding OffsetBits:325 SizeBits:1] map[Name:resetting_device OffsetBits:326 SizeBits:1] map[Name:authorized OffsetBits:327 SizeBits:1] map[Name:wireless_status OffsetBits:352 SizeBits:32] map[Name:wireless_status_work OffsetBits:384 SizeBits:576] map[Name:dev OffsetBits:960 SizeBits:11776] map[Name:usb_dev OffsetBits:12736 SizeBits:64] map[Name:reset_ws OffsetBits:12800 SizeBits:576]]]
|
| 27/2 |
2026/07/30 12:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 32657
output: 21
thoughts: 67
Thoughts: **Dissecting the Memory Layout**
Okay, so I'm looking at this memory layout, specifically within this USB interface structure. I see that `usb_interface->dev` sits at an offset of 960 bits, which translates to a clean 120 bytes. Now, I'm trying to figure out the relationship between `usb_interface->dev` and `parent`. Logically, if `parent` *was* `usb_interface->dev`, it should also be at offset 120, right? But that's not what I'm seeing. `parent` is actually at offset 176. That discrepancy throws a red flag. I need to understand why. This likely points to the way the net device is set up. Time to check the structure definition for `struct net_device` to see what fields are defined within. This should clear up the misalignment.
|
| 28/2 |
2026/07/30 12:19 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:__cacheline_group_begin__net_device_read_tx OffsetBits:0 SizeBits:0] map[Name: OffsetBits:0 SizeBits:64] map[Name:netdev_ops OffsetBits:64 SizeBits:64] map[Name:header_ops OffsetBits:128 SizeBits:64] map[Name:_tx OffsetBits:192 SizeBits:64] map[Name:gso_partial_features OffsetBits:256 SizeBits:64] map[Name:real_num_tx_queues OffsetBits:320 SizeBits:32] map[Name:gso_max_size OffsetBits:352 SizeBits:32] map[Name:gso_ipv4_max_size OffsetBits:384 SizeBits:32] map[Name:gso_max_segs OffsetBits:416 SizeBits:16] map[Name:num_tc OffsetBits:432 SizeBits:16] map[Name:mtu OffsetBits:448 SizeBits:32] map[Name:needed_headroom OffsetBits:480 SizeBits:16] map[Name:tc_to_txq OffsetBits:496 SizeBits:512] map[Name:xps_maps OffsetBits:1024 SizeBits:128] map[Name:nf_hooks_egress OffsetBits:1152 SizeBits:64] map[Name:tcx_egress OffsetBits:1216 SizeBits:64] map[Name:__cacheline_group_end__net_device_read_tx OffsetBits:1280 SizeBits:0] map[Name:__cacheline_group_begin__net_device_read_txrx OffsetBits:1280 SizeBits:0] map[Name: OffsetBits:1280 SizeBits:64] map[Name:state OffsetBits:1344 SizeBits:64] map[Name:flags OffsetBits:1408 SizeBits:32] map[Name:hard_header_len OffsetBits:1440 SizeBits:16] map[Name:pcpu_stat_type OffsetBits:1456 SizeBits:8] map[Name:features OffsetBits:1472 SizeBits:64] map[Name:ip6_ptr OffsetBits:1536 SizeBits:64] map[Name:__cacheline_group_end__net_device_read_txrx OffsetBits:1600 SizeBits:0] map[Name:__cacheline_group_begin__net_device_read_rx OffsetBits:1600 SizeBits:0] map[Name:xdp_prog OffsetBits:1600 SizeBits:64] map[Name:ptype_specific OffsetBits:1664 SizeBits:128] map[Name:ifindex OffsetBits:1792 SizeBits:32] map[Name:real_num_rx_queues OffsetBits:1824 SizeBits:32] map[Name:_rx OffsetBits:1856 SizeBits:64] map[Name:gro_max_size OffsetBits:1920 SizeBits:32] map[Name:gro_ipv4_max_size OffsetBits:1952 SizeBits:32] map[Name:rx_handler OffsetBits:1984 SizeBits:64] map[Name:rx_handler_data OffsetBits:2048 SizeBits:64] map[Name:nd_net OffsetBits:2112 SizeBits:64] map[Name:npinfo OffsetBits:2176 SizeBits:64] map[Name:tcx_ingress OffsetBits:2240 SizeBits:64] map[Name:__cacheline_group_end__net_device_read_rx OffsetBits:2304 SizeBits:0] map[Name:name OffsetBits:2304 SizeBits:128] map[Name:name_node OffsetBits:2432 SizeBits:64] map[Name:ifalias OffsetBits:2496 SizeBits:64] map[Name:mem_end OffsetBits:2560 SizeBits:64] map[Name:mem_start OffsetBits:2624 SizeBits:64] map[Name:base_addr OffsetBits:2688 SizeBits:64] map[Name:dev_list OffsetBits:2752 SizeBits:128] map[Name:napi_list OffsetBits:2880 SizeBits:128] map[Name:unreg_list OffsetBits:3008 SizeBits:128] map[Name:close_list OffsetBits:3136 SizeBits:128] map[Name:ptype_all OffsetBits:3264 SizeBits:128] map[Name:adj_list OffsetBits:3392 SizeBits:256] map[Name:xdp_features OffsetBits:3648 SizeBits:32] map[Name:xdp_metadata_ops OffsetBits:3712 SizeBits:64] map[Name:xsk_tx_metadata_ops OffsetBits:3776 SizeBits:64] map[Name:gflags OffsetBits:3840 SizeBits:16] map[Name:needed_tailroom OffsetBits:3856 SizeBits:16] map[Name:hw_features OffsetBits:3904 SizeBits:64] map[Name:wanted_features OffsetBits:3968 SizeBits:64] map[Name:vlan_features OffsetBits:4032 SizeBits:64] map[Name:hw_enc_features OffsetBits:4096 SizeBits:64] map[Name:mpls_features OffsetBits:4160 SizeBits:64] map[Name:mangleid_features OffsetBits:4224 SizeBits:64] map[Name:min_mtu OffsetBits:4288 SizeBits:32] map[Name:max_mtu OffsetBits:4320 SizeBits:32] map[Name:type OffsetBits:4352 SizeBits:16] map[Name:min_header_len OffsetBits:4368 SizeBits:8] map[Name:name_assign_type OffsetBits:4376 SizeBits:8] map[Name:group OffsetBits:4384 SizeBits:32] map[Name:stats OffsetBits:4416 SizeBits:1472] map[Name:core_stats OffsetBits:5888 SizeBits:64] map[Name:carrier_up_count OffsetBits:5952 SizeBits:32] map[Name:carrier_down_count OffsetBits:5984 SizeBits:32] map[Name:ethtool_ops OffsetBits:6016 SizeBits:64] map[Name:l3mdev_ops OffsetBits:6080 SizeBits:64] map[Name:ndisc_ops OffsetBits:6144 SizeBits:64] map[Name:xfrmdev_ops OffsetBits:6208 SizeBits:64] map[Name:tlsdev_ops OffsetBits:6272 SizeBits:64] map[Name:operstate OffsetBits:6336 SizeBits:32] map[Name:link_mode OffsetBits:6368 SizeBits:8] map[Name:if_port OffsetBits:6376 SizeBits:8] map[Name:dma OffsetBits:6384 SizeBits:8] map[Name:perm_addr OffsetBits:6392 SizeBits:256] map[Name:addr_assign_type OffsetBits:6648 SizeBits:8] map[Name:addr_len OffsetBits:6656 SizeBits:8] map[Name:upper_level OffsetBits:6664 SizeBits:8] map[Name:lower_level OffsetBits:6672 SizeBits:8] map[Name:threaded OffsetBits:6680 SizeBits:8] map[Name:neigh_priv_len OffsetBits:6688 SizeBits:16] map[Name:dev_id OffsetBits:6704 SizeBits:16] map[Name:dev_port OffsetBits:6720 SizeBits:16] map[Name:irq OffsetBits:6752 SizeBits:32] map[Name:priv_len OffsetBits:6784 SizeBits:32] map[Name:addr_list_lock OffsetBits:6848 SizeBits:1024] map[Name:uc OffsetBits:7872 SizeBits:256] map[Name:mc OffsetBits:8128 SizeBits:256] map[Name:dev_addrs OffsetBits:8384 SizeBits:256] map[Name:queues_kset OffsetBits:8640 SizeBits:64] map[Name:unlink_list OffsetBits:8704 SizeBits:128] map[Name:promiscuity OffsetBits:8832 SizeBits:32] map[Name:allmulti OffsetBits:8864 SizeBits:32] map[Name:uc_promisc OffsetBits:8896 SizeBits:8] map[Name:work_node OffsetBits:8960 SizeBits:128] map[Name:work_tracker OffsetBits:9088 SizeBits:64] map[Name:work_pending OffsetBits:9152 SizeBits:64] map[Name:work_core_pending OffsetBits:9216 SizeBits:64] map[Name:rx_mode_addr_cache OffsetBits:9280 SizeBits:256] map[Name:rx_mode_retry_timer OffsetBits:9536 SizeBits:640] map[Name:rx_mode_retry_count OffsetBits:10176 SizeBits:32] map[Name:nested_level OffsetBits:10208 SizeBits:8] map[Name:ip_ptr OffsetBits:10240 SizeBits:64] map[Name:fib_nh_head OffsetBits:10304 SizeBits:64] map[Name:vlan_info OffsetBits:10368 SizeBits:64] map[Name:dsa_ptr OffsetBits:10432 SizeBits:64] map[Name:tipc_ptr OffsetBits:10496 SizeBits:64] map[Name:ieee80211_ptr OffsetBits:10560 SizeBits:64] map[Name:ieee802154_ptr OffsetBits:10624 SizeBits:64] map[Name:mpls_ptr OffsetBits:10688 SizeBits:64] map[Name:mctp_ptr OffsetBits:10752 SizeBits:64] map[Name:psp_dev OffsetBits:10816 SizeBits:64] map[Name:dev_addr OffsetBits:10880 SizeBits:64] map[Name:num_rx_queues OffsetBits:10944 SizeBits:32] map[Name:xdp_zc_max_segs OffsetBits:10976 SizeBits:32] map[Name:ingress_queue OffsetBits:11008 SizeBits:64] map[Name:nf_hooks_ingress OffsetBits:11072 SizeBits:64] map[Name:broadcast OffsetBits:11136 SizeBits:256] map[Name:rx_cpu_rmap OffsetBits:11392 SizeBits:64] map[Name:index_hlist OffsetBits:11456 SizeBits:128] map[Name:num_tx_queues OffsetBits:11584 SizeBits:32] map[Name:qdisc OffsetBits:11648 SizeBits:64] map[Name:tx_queue_len OffsetBits:11712 SizeBits:32] map[Name:tx_global_lock OffsetBits:11776 SizeBits:1024] map[Name:xdp_bulkq OffsetBits:12800 SizeBits:64] map[Name:qdisc_hash OffsetBits:12864 SizeBits:1024] map[Name:watchdog_timer OffsetBits:13888 SizeBits:640] map[Name:watchdog_timeo OffsetBits:14528 SizeBits:32] map[Name:watchdog_lock OffsetBits:14592 SizeBits:1024] map[Name:watchdog_ref_held OffsetBits:15616 SizeBits:8] map[Name:proto_down_reason OffsetBits:15648 SizeBits:32] map[Name:todo_list OffsetBits:15680 SizeBits:128] map[Name:dev_refcnt OffsetBits:15808 SizeBits:32] map[Name:refcnt_tracker OffsetBits:15872 SizeBits:1472] map[Name:link_watch_list OffsetBits:17344 SizeBits:128] map[Name:reg_state OffsetBits:17472 SizeBits:8] map[Name:dismantle OffsetBits:17480 SizeBits:8] map[Name:moving_ns OffsetBits:17488 SizeBits:8] map[Name:rtnl_link_initializing OffsetBits:17496 SizeBits:8] map[Name:needs_free_netdev OffsetBits:17504 SizeBits:8] map[Name:priv_destructor OffsetBits:17536 SizeBits:64] map[Name:ml_priv OffsetBits:17600 SizeBits:64] map[Name:ml_priv_type OffsetBits:17664 SizeBits:32] map[Name:garp_port OffsetBits:17728 SizeBits:64] map[Name:mrp_port OffsetBits:17792 SizeBits:64] map[Name:dm_private OffsetBits:17856 SizeBits:64] map[Name:dev OffsetBits:17920 SizeBits:11776] map[Name:sysfs_groups OffsetBits:29696 SizeBits:320] map[Name:sysfs_rx_queue_group OffsetBits:30016 SizeBits:64] map[Name:rtnl_link_ops OffsetBits:30080 SizeBits:64] map[Name:stat_ops OffsetBits:30144 SizeBits:64] map[Name:queue_mgmt_ops OffsetBits:30208 SizeBits:64] map[Name:tso_max_size OffsetBits:30272 SizeBits:32] map[Name:tso_max_segs OffsetBits:30304 SizeBits:16] map[Name:dcbnl_ops OffsetBits:30336 SizeBits:64] map[Name:prio_tc_map OffsetBits:30400 SizeBits:128] map[Name:priomap OffsetBits:30528 SizeBits:64] map[Name:link_topo OffsetBits:30592 SizeBits:64] map[Name:phydev OffsetBits:30656 SizeBits:64] map[Name:sfp_bus OffsetBits:30720 SizeBits:64] map[Name:qdisc_tx_busylock OffsetBits:30784 SizeBits:64] map[Name:proto_down OffsetBits:30848 SizeBits:8] map[Name:irq_affinity_auto OffsetBits:30856 SizeBits:8] map[Name:rx_cpu_rmap_auto OffsetBits:30864 SizeBits:8] map[Name:see_all_hwtstamp_requests OffsetBits:30872 SizeBits:1] map[Name:change_proto_down OffsetBits:30873 SizeBits:1] map[Name:netns_immutable OffsetBits:30874 SizeBits:1] map[Name:fcoe_mtu OffsetBits:30875 SizeBits:1] map[Name:net_notifier_list OffsetBits:30912 SizeBits:128] map[Name:macsec_ops OffsetBits:31040 SizeBits:64] map[Name:udp_tunnel_nic_info OffsetBits:31104 SizeBits:64] map[Name:udp_tunnel_nic OffsetBits:31168 SizeBits:64] map[Name:cfg OffsetBits:31232 SizeBits:64] map[Name:cfg_pending OffsetBits:31296 SizeBits:64] map[Name:ethtool OffsetBits:31360 SizeBits:64] map[Name:xdp_state OffsetBits:31424 SizeBits:384] map[Name:dev_addr_shadow OffsetBits:31808 SizeBits:256] map[Name:linkwatch_dev_tracker OffsetBits:32064 SizeBits:64] map[Name:watchdog_dev_tracker OffsetBits:32128 SizeBits:64] map[Name:dev_registered_tracker OffsetBits:32192 SizeBits:64] map[Name:offload_xstats_l3 OffsetBits:32256 SizeBits:64] map[Name:devlink_port OffsetBits:32320 SizeBits:64] map[Name:page_pools OffsetBits:32384 SizeBits:64] map[Name:irq_moder OffsetBits:32448 SizeBits:64] map[Name:max_pacing_offload_horizon OffsetBits:32512 SizeBits:64] map[Name:napi_config OffsetBits:32576 SizeBits:64] map[Name:num_napi_configs OffsetBits:32640 SizeBits:32] map[Name:napi_defer_hard_irqs OffsetBits:32672 SizeBits:32] map[Name:gro_flush_timeout OffsetBits:32704 SizeBits:64] map[Name:up OffsetBits:32768 SizeBits:8] map[Name:request_ops_lock OffsetBits:32776 SizeBits:8] map[Name:lock OffsetBits:32832 SizeBits:1024] map[Name:net_shaper_hierarchy OffsetBits:33856 SizeBits:64] map[Name:neighbours OffsetBits:33920 SizeBits:128] map[Name:hwprov OffsetBits:34048 SizeBits:64] map[Name:priv OffsetBits:34304 SizeBits:0]]]
|
| 29/2 |
2026/07/30 12:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 37852
output: 21
thoughts: 357
Thoughts: **Deconstructing the KASAN Report**
Okay, let's break this down. KASAN is flagging an issue, and I need to trace the pointer. First, the report says the bug involves accessing `net_device->dev` at offset 2240 bytes. Then I remember we are dealing with `i2c_adapter` and `i2c_adapter->dev` is at offset 304 bytes. But, wait, the crucial part is `parent`. If `parent` is actually `adapter->dev.parent`, then `parent` is a pointer to `struct device`.
Now, the KASAN report specifies the buggy address is `ffff8880270b4108`, which corresponds to `parent->type`. I know from the structure definition that `parent->type` is at offset 88 bytes within `struct device`. Therefore, I can calculate that the `parent` itself is located at address `ffff8880270b40b0`. So, `ffff8880270b40b0` is the actual address of the `parent` device, and crucially it is the value stored in the `adapter->dev.parent` pointer.
The report also indicates that the entire memory region from `ffff8880270b4000` to `ffff8880270b5000` (a 4096-byte region) has been freed. The address of `parent` (`ffff8880270b40b0`) is inside this freed region. This means the `parent` device itself must have been allocated somewhere *within* that 4096-byte block. Now the question is what is the object that has a `struct device` at offset 176? Let me check `struct usb_device`.
|
| 30/2 |
2026/07/30 12:19 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:devnum OffsetBits:0 SizeBits:32] map[Name:devpath OffsetBits:32 SizeBits:128] map[Name:route OffsetBits:160 SizeBits:32] map[Name:state OffsetBits:192 SizeBits:32] map[Name:speed OffsetBits:224 SizeBits:32] map[Name:rx_lanes OffsetBits:256 SizeBits:32] map[Name:tx_lanes OffsetBits:288 SizeBits:32] map[Name:ssp_rate OffsetBits:320 SizeBits:32] map[Name:tt OffsetBits:384 SizeBits:64] map[Name:ttport OffsetBits:448 SizeBits:32] map[Name:toggle OffsetBits:480 SizeBits:64] map[Name:parent OffsetBits:576 SizeBits:64] map[Name:bus OffsetBits:640 SizeBits:64] map[Name:ep0 OffsetBits:704 SizeBits:704] map[Name:dev OffsetBits:1408 SizeBits:11776] map[Name:descriptor OffsetBits:13184 SizeBits:144] map[Name:bos OffsetBits:13376 SizeBits:64] map[Name:config OffsetBits:13440 SizeBits:64] map[Name:actconfig OffsetBits:13504 SizeBits:64] map[Name:ep_in OffsetBits:13568 SizeBits:1024] map[Name:ep_out OffsetBits:14592 SizeBits:1024] map[Name:rawdescriptors OffsetBits:15616 SizeBits:64] map[Name:bus_mA OffsetBits:15680 SizeBits:16] map[Name:portnum OffsetBits:15696 SizeBits:8] map[Name:level OffsetBits:15704 SizeBits:8] map[Name:devaddr OffsetBits:15712 SizeBits:8] map[Name:can_submit OffsetBits:15720 SizeBits:1] map[Name:persist_enabled OffsetBits:15721 SizeBits:1] map[Name:reset_in_progress OffsetBits:15722 SizeBits:1] map[Name:have_langid OffsetBits:15723 SizeBits:1] map[Name:authorized OffsetBits:15724 SizeBits:1] map[Name:authenticated OffsetBits:15725 SizeBits:1] map[Name:lpm_capable OffsetBits:15726 SizeBits:1] map[Name:lpm_devinit_allow OffsetBits:15727 SizeBits:1] map[Name:usb2_hw_lpm_capable OffsetBits:15728 SizeBits:1] map[Name:usb2_hw_lpm_besl_capable OffsetBits:15729 SizeBits:1] map[Name:usb2_hw_lpm_enabled OffsetBits:15730 SizeBits:1] map[Name:usb2_hw_lpm_allowed OffsetBits:15731 SizeBits:1] map[Name:usb3_lpm_u1_enabled OffsetBits:15732 SizeBits:1] map[Name:usb3_lpm_u2_enabled OffsetBits:15733 SizeBits:1] map[Name:string_langid OffsetBits:15744 SizeBits:32] map[Name:product OffsetBits:15808 SizeBits:64] map[Name:manufacturer OffsetBits:15872 SizeBits:64] map[Name:serial OffsetBits:15936 SizeBits:64] map[Name:filelist OffsetBits:16000 SizeBits:128] map[Name:maxchild OffsetBits:16128 SizeBits:32] map[Name:quirks OffsetBits:16160 SizeBits:32] map[Name:urbnum OffsetBits:16192 SizeBits:32] map[Name:active_duration OffsetBits:16256 SizeBits:64] map[Name:connect_time OffsetBits:16320 SizeBits:64] map[Name:do_remote_wakeup OffsetBits:16384 SizeBits:1] map[Name:reset_resume OffsetBits:16385 SizeBits:1] map[Name:port_is_suspended OffsetBits:16386 SizeBits:1] map[Name:offload_pm_locked OffsetBits:16387 SizeBits:1] map[Name:offload_usage OffsetBits:16416 SizeBits:32] map[Name:offload_lock OffsetBits:16448 SizeBits:1024] map[Name:tunnel_mode OffsetBits:17472 SizeBits:32] map[Name:usb4_link OffsetBits:17536 SizeBits:64] map[Name:slot_id OffsetBits:17600 SizeBits:32] map[Name:l1_params OffsetBits:17632 SizeBits:64] map[Name:u1_params OffsetBits:17696 SizeBits:128] map[Name:u2_params OffsetBits:17824 SizeBits:128] map[Name:lpm_disable_count OffsetBits:17952 SizeBits:32] map[Name:hub_delay OffsetBits:17984 SizeBits:16] map[Name:use_generic_driver OffsetBits:18000 SizeBits:1]]]
|
| 31/2 |
2026/07/30 12:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 40132
output: 21
thoughts: 540
Thoughts: **Analyzing a Potential Use-After-Free Vulnerability**
Okay, let's break this down. First, I've got confirmation: `usb_device->dev` is indeed at an offset of 176 bytes. This means the `parent` pointer of something else is referencing it. I quickly deduce that `parent` must be pointing to the `usb_device->dev` member itself. Therefore, the parent device is a `usb_device`, and I've identified the memory region where that `usb_device` was allocated as `[ffff8880270b4000, ffff8880270b5000)`. The size of the `usb_device` structure is about 2251 bytes, so it fits nicely in a `kmalloc-4k` allocation.
So, the next thing I realize is that the freed object is a `struct usb_device`. Now, the crucial connection: an `i2c_adapter`'s `adapter->dev.parent` is pointing to `&usb_device->dev`. This establishes that the `i2c_adapter` is a child of the `usb_device`. But the real question is how the adapter is being kept alive in spite of the free.
The next thought is to figure out why the `i2c_adapter` continues to be accessed even after the parent `usb_device` is freed. Aha! `/dev/i2c-X`! I see now that `i2cdev_open` is called, and that retrieves the `i2c_adapter` via `i2c_get_adapter`. Then, I remember that `i2c_get_adapter` increments the refcount of `adapter->dev`, not the refcount of the `adapter->dev.parent`! This seems significant.
Then the key pieces fall into place: `device_add` *does* increment the parent's refcount. During `i2c_adapter` registration, `device_add(&adapter->dev)` is called, so this must happen. Crucially, `device_add` calls `get_device(dev->parent)`. This means that as long as the `adapter->dev` is registered, the parent's refcount is kept alive.
Then when I think about unregistration: When the `i2c_adapter` is unregistered (e.g., during USB device disconnection), `device_unregister(&adapter->dev)` is called. That call drops the parent's refcount! But, `i2c_get_adapter` is keeping `adapter->dev` alive, even after unregistration. I see that this is a conflict, that I have to think about now: If the adapter is unregistered, its `dev` is kept alive by `i2c_get_adapter` and so its parent could be freed. But `device_del` *drops* the parent's refcount! So, I need to check `device_del` to confirm all this!
|
| 32/2 |
2026/07/30 12:19 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3902: /**
3903: * device_del - delete device from system.
3904: * @dev: device.
3905: *
3906: * This is the first part of the device unregistration
3907: * sequence. This removes the device from the lists we control
3908: * from here, has it removed from the other driver model
3909: * subsystems it was added to in device_add(), and removes it
3910: * from the kobject hierarchy.
3911: *
3912: * NOTE: this should be called manually _iff_ device_add() was
3913: * also called manually.
3914: */
3915: void device_del(struct device *dev)
3916: {
3917: struct subsys_private *sp;
3918: struct device *parent = dev->parent;
3919: struct kobject *glue_dir = NULL;
3920: struct class_interface *class_intf;
3921: unsigned int noio_flag;
3922:
3923: device_lock(dev);
3924: kill_device(dev);
3925: device_unlock(dev);
3926:
3927: if (dev->fwnode && dev->fwnode->dev == dev)
3928: dev->fwnode->dev = NULL;
3929:
3930: /* Notify clients of device removal. This call must come
3931: * before dpm_sysfs_remove().
3932: */
3933: noio_flag = memalloc_noio_save();
3934: bus_notify(dev, BUS_NOTIFY_DEL_DEVICE);
3935:
3936: dpm_sysfs_remove(dev);
3937: if (parent)
3938: klist_del(&dev->p->knode_parent);
3939: if (MAJOR(dev->devt)) {
3940: devtmpfs_delete_node(dev);
3941: device_remove_sys_dev_entry(dev);
3942: device_remove_file(dev, &dev_attr_dev);
3943: }
3944:
3945: sp = class_to_subsys(dev->class);
3946: if (sp) {
3947: device_remove_class_symlinks(dev);
3948:
3949: mutex_lock(&sp->mutex);
3950: /* notify any interfaces that the device is now gone */
3951: list_for_each_entry(class_intf, &sp->interfaces, node)
3952: if (class_intf->remove_dev)
3953: class_intf->remove_dev(dev);
3954: /* remove the device from the class list */
3955: klist_del(&dev->p->knode_class);
3956: mutex_unlock(&sp->mutex);
3957: subsys_put(sp);
3958: }
3959: device_remove_file(dev, &dev_attr_uevent);
3960: device_remove_attrs(dev);
3961: bus_remove_device(dev);
3962: device_pm_remove(dev);
3963: driver_deferred_probe_del(dev);
3964: device_platform_notify_remove(dev);
3965: device_links_purge(dev);
3966:
3967: /*
3968: * If a device does not have a driver attached, we need to clean
3969: * up any managed resources. We do this in device_release(), but
3970: * it's never called (and we leak the device) if a managed
3971: * resource holds a reference to the device. So release all
3972: * managed resources here, like we do in driver_detach(). We
3973: * still need to do so again in device_release() in case someone
3974: * adds a new resource after this point, though.
3975: */
3976: devres_release_all(dev);
3977:
3978: bus_notify(dev, BUS_NOTIFY_REMOVED_DEVICE);
3979: kobject_uevent(&dev->kobj, KOBJ_REMOVE);
3980: glue_dir = get_glue_dir(dev);
3981: kobject_del(&dev->kobj);
3982: cleanup_glue_dir(dev, glue_dir);
3983: memalloc_noio_restore(noio_flag);
3984: put_device(parent);
3985: }
SourceFile:drivers/base/core.c]
|
| 33/2 |
2026/07/30 12:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 42684
output: 31
thoughts: 478
Thoughts: **Use-After-Free Vulnerability in I2C Adapter Handling**
Okay, so here's what I've figured out. `device_del` calls `put_device(parent)`. That's the key. If an `i2c_adapter` is unregistered β say, the USB device it's attached to is disconnected β then `device_del(&adapter->dev)` gets called. This *should* decrement the reference count of the adapter's parent, which in this case is a `usb_device`. And if that `usb_device` was only being held by this reference, boom, it's freed. No surprises there.
But here's the kicker: `i2c_get_adapter` *holds* a reference to the `adapter->dev`, so the `i2c_adapter` itself doesn't get freed. Makes sense.
Then, here's where it all goes sideways. An `i2cdev_ioctl_smbus` call eventually leads to `i2c_adapter_depth`. And guess what `i2c_adapter_depth` does? It accesses `adapter->dev.parent->type`. But *that* `adapter->dev.parent` is now pointing to freed memory, the previously freed `usb_device`! It's a textbook use-after-free, plain and simple.
The real problem seems to be the assumption that the `adapter->dev.parent` will remain valid after `device_del` is called. It *traverses* that pointer. I see. Accessing `adapter->dev.parent` after `device_del` is not safe, and the `dev->parent` pointer is not set to NULL upon deletion, it just gets left pointing at the freed memory.
So, how can we trigger this? Here's my reproduction plan:
1. We need a USB device that registers an I2C adapter.
2. Then, open the corresponding `/dev/i2c-X` device file.
3. Unplug the USB device. This'll trigger the unregistration of the I2C adapter and the freeing of the `usb_device`.
4. Finally, call the `I2C_SMBUS` ioctl on that open file descriptor.
5. This ioctl should execute `i2c_adapter_depth` and trigger the use-after-free.
Now I need to find which USB driver is registering these I2C adapters... time to search the source!
|
| 34/2 |
2026/07/30 12:19 |
tool |
grepper |
0m
Error:
Args: map[Expression:i2c_add_adapter PathPrefix:drivers/usb/]
Results:
|
| 35/2 |
2026/07/30 12:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 43747
output: 33
thoughts: 31
Thoughts: Here's my attempt at summarizing that thought process, tailored for an expert audience:
**Considering the I2C Adapter Addition**
Okay, so I'm thinking about how an I2C adapter is actually integrated, and I'm realizing `i2c_add_adapter` isn't necessarily the only entry point. There's a decent chance that it could be called indirectly through some abstraction layer or wrapper function. I'm wondering if there are any other possible paths to consider, like a function such as `i2c_bit_add_bus` might be involved instead. I'll need to remember that when I'm assessing the entire integration path, there might be some less obvious places where the adapter initialization happens, perhaps hidden within some higher-level abstraction. I need to keep that in mind when I dig through the code.
|
| 36/2 |
2026/07/30 12:19 |
tool |
grepper |
0m
Error:
Args: map[Expression:i2c_.*add_.*adapter PathPrefix:drivers/usb/]
Results:
|
| 37/2 |
2026/07/30 12:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 44003
output: 30
thoughts: 19
Thoughts: Okay, here's my summarized thought process, presented as if I were thinking it:
**Digging into the USB Driver Landscape**
Alright, time to get my hands dirty. I need to find the relevant USB driver code for I2C adapters. First, a targeted approach is the best way to start, so let's use a straightforward search. Let's see, the driver is likely within the `drivers/usb/` directory. That's the logical starting point. Now, to zero in on the I2C part, I need to look for `i2c_adapter` within that USB directory. That should lead me to the USB driver files dealing with I2C devices. From there, I can analyze the driver's implementation. Let's see what we come up with.
|
| 38/2 |
2026/07/30 12:19 |
tool |
grepper |
0m
Args: map[Expression:struct i2c_adapter PathPrefix:drivers/usb/]
Results: map[Output:drivers/usb/misc/usb251xb.c=243=static int usb251x_check_gpio_chip(struct usb251xb *hub)
--
drivers/usb/misc/usb251xb.c-245- struct gpio_chip *gc = gpiod_to_chip(hub->gpio_reset);
drivers/usb/misc/usb251xb.c:246: struct i2c_adapter *adap;
drivers/usb/misc/usb251xb.c-247- int ret;
--
drivers/usb/typec/tcpm/fusb302.c=1689=static int fusb302_probe(struct i2c_client *client)
--
drivers/usb/typec/tcpm/fusb302.c-1691- struct fusb302_chip *chip;
drivers/usb/typec/tcpm/fusb302.c:1692: struct i2c_adapter *adapter = client->adapter;
drivers/usb/typec/tcpm/fusb302.c-1693- struct auxiliary_device *bridge_dev;
--
drivers/usb/typec/ucsi/ucsi_ccg.c=238=static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
--
drivers/usb/typec/ucsi/ucsi_ccg.c-240- struct i2c_client *client = uc->client;
drivers/usb/typec/ucsi/ucsi_ccg.c:241: const struct i2c_adapter_quirks *quirks = client->adapter->quirks;
drivers/usb/typec/ucsi/ucsi_ccg.c-242- unsigned char buf[2];
]
|
| 39/2 |
2026/07/30 12:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 44696
output: 33
thoughts: 34
Thoughts: Here's my summary, as the thought process of a media expert:
**Investigating the I2C Adapter Registration**
Okay, hold on a second. That `i2c_adapter`... I recall seeing it registered by something within the USB media driver space. That's unusual, but my intuition says that's where I need to look. Alright, time to dive into `drivers/media/usb/`. Let's see what's happening in there. I'm going to carefully review the code base in that specific area to understand this, and the context of that I2C adapter registration. I'll need to remember all the various USB devices and interfaces that have I2C dependencies and look to how the registration process is implemented.
|
| 40/2 |
2026/07/30 12:20 |
tool |
grepper |
0m
Args: map[Expression:i2c_add_adapter PathPrefix:drivers/media/usb/]
Results: map[Output:drivers/media/usb/au0828/au0828-i2c.c=354=int au0828_i2c_register(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-i2c.c-373-#endif
drivers/media/usb/au0828/au0828-i2c.c:374: i2c_add_adapter(&dev->i2c_adap);
drivers/media/usb/au0828/au0828-i2c.c-375-
--
drivers/media/usb/cx231xx/cx231xx-i2c.c=514=int cx231xx_i2c_register(struct cx231xx_i2c *bus)
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-527- i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
drivers/media/usb/cx231xx/cx231xx-i2c.c:528: bus->i2c_rc = i2c_add_adapter(&bus->i2c_adap);
drivers/media/usb/cx231xx/cx231xx-i2c.c-529-
--
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c=56=static int dvb_usbv2_i2c_init(struct dvb_usb_device *d)
--
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c-68-
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c:69: ret = i2c_add_adapter(&d->i2c_adap);
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c-70- if (ret < 0) {
--
drivers/media/usb/dvb-usb/dvb-usb-i2c.c=11=int dvb_usb_i2c_init(struct dvb_usb_device *d)
--
drivers/media/usb/dvb-usb/dvb-usb-i2c.c-30-
drivers/media/usb/dvb-usb/dvb-usb-i2c.c:31: ret = i2c_add_adapter(&d->i2c_adap);
drivers/media/usb/dvb-usb/dvb-usb-i2c.c-32- if (ret < 0) {
--
drivers/media/usb/em28xx/em28xx-i2c.c=970=int em28xx_i2c_register(struct em28xx *dev, unsigned int bus,
--
drivers/media/usb/em28xx/em28xx-i2c.c-991-
drivers/media/usb/em28xx/em28xx-i2c.c:992: retval = i2c_add_adapter(&dev->i2c_adap[bus]);
drivers/media/usb/em28xx/em28xx-i2c.c-993- if (retval < 0) {
drivers/media/usb/em28xx/em28xx-i2c.c-994- dev_err(&dev->intf->dev,
drivers/media/usb/em28xx/em28xx-i2c.c:995: "%s: i2c_add_adapter failed! retval [%d]\n",
drivers/media/usb/em28xx/em28xx-i2c.c-996- __func__, retval);
--
drivers/media/usb/go7007/go7007-i2c.c=204=int go7007_i2c_init(struct go7007 *go)
--
drivers/media/usb/go7007/go7007-i2c.c-209- i2c_set_adapdata(&go->i2c_adapter, go);
drivers/media/usb/go7007/go7007-i2c.c:210: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
drivers/media/usb/go7007/go7007-i2c.c-211- dev_err(go->dev,
drivers/media/usb/go7007/go7007-i2c.c:212: "go7007-i2c: error: i2c_add_adapter failed\n");
drivers/media/usb/go7007/go7007-i2c.c-213- return -1;
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1171- i2c_set_adapdata(&go->i2c_adapter, go);
drivers/media/usb/go7007/go7007-usb.c:1172: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
drivers/media/usb/go7007/go7007-usb.c:1173: dev_err(go->dev, "error: i2c_add_adapter failed\n");
drivers/media/usb/go7007/go7007-usb.c-1174- goto allocfail;
--
drivers/media/usb/hdpvr/hdpvr-i2c.c=180=int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
--
drivers/media/usb/hdpvr/hdpvr-i2c.c-188-
drivers/media/usb/hdpvr/hdpvr-i2c.c:189: return i2c_add_adapter(&dev->i2c_adapter);
drivers/media/usb/hdpvr/hdpvr-i2c.c-190-}
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c=591=void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-627- i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c:628: i2c_add_adapter(&hdw->i2c_adap);
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-629- if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
--
drivers/media/usb/stk1160/stk1160-i2c.c=247=int stk1160_i2c_register(struct stk1160 *dev)
--
drivers/media/usb/stk1160/stk1160-i2c.c-257-
drivers/media/usb/stk1160/stk1160-i2c.c:258: rc = i2c_add_adapter(&dev->i2c_adap);
drivers/media/usb/stk1160/stk1160-i2c.c-259- if (rc < 0) {
--
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c=1597=static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
--
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c-1655-
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c:1656: result = i2c_add_adapter(&ttusb->i2c_adap);
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c-1657- if (result)
]
|
| 41/2 |
2026/07/30 12:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 47124
output: 24
thoughts: 37
Thoughts: **Analyzing the KASAN Report and Object Allocation**
Okay, so the KASAN report is highlighting an issue involving a freed object. The report explicitly mentions this object was allocated via `kmalloc-4k`. Right, that's the key starting point. Now, I need to understand the context of this allocation. What's likely to be allocated with `kmalloc-4k` in this section of the code? I'm going to quickly check the size of `struct dvb_usb_device`. Knowing its size will help confirm or deny this suspicion, since the issue relates to a `kmalloc-4k` object. Is there any way this data structure relates to the freed memory?
|
| 42/2 |
2026/07/30 12:20 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:props OffsetBits:0 SizeBits:29760] map[Name:desc OffsetBits:29760 SizeBits:64] map[Name:udev OffsetBits:29824 SizeBits:64] map[Name:state OffsetBits:29888 SizeBits:32] map[Name:powered OffsetBits:29920 SizeBits:32] map[Name:data_mutex OffsetBits:29952 SizeBits:1024] map[Name:usb_mutex OffsetBits:30976 SizeBits:1024] map[Name:i2c_mutex OffsetBits:32000 SizeBits:1024] map[Name:i2c_adap OffsetBits:33024 SizeBits:17024] map[Name:num_adapters_initialized OffsetBits:50048 SizeBits:32] map[Name:adapter OffsetBits:50112 SizeBits:67840] map[Name:rc_dev OffsetBits:117952 SizeBits:64] map[Name:input_dev OffsetBits:118016 SizeBits:64] map[Name:rc_phys OffsetBits:118080 SizeBits:512] map[Name:rc_query_work OffsetBits:118592 SizeBits:1344] map[Name:last_event OffsetBits:119936 SizeBits:32] map[Name:last_state OffsetBits:119968 SizeBits:32] map[Name:owner OffsetBits:120000 SizeBits:64] map[Name:priv OffsetBits:120064 SizeBits:64]]]
|
| 43/2 |
2026/07/30 12:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 47798
output: 23
thoughts: 158
Thoughts: **Analyzing a Potential Memory Management Issue**
Okay, let's break this down. First, I see that this `dvb_usb_device` structure is fairly large β 15016 bytes, allocated from `kmalloc-16k`, which makes sense given the size. Then, the observation that the freed object is a `struct usb_device` immediately triggers a flag. I know the size of a `struct usb_device` β 2251 bytes, I've checked that before. Now, I recall that `usb_device->dev` resides at offset 176 bytes. Aha! This is interesting; because I can see that `parent` is also at offset 176 bytes, in the freed object! So it seems that the freed object *is* the `struct usb_device` itself. Now, this further suggests the device is being allocated via `usb_alloc_dev` which I would expect.
|
| 44/2 |
2026/07/30 12:20 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 628: /**
629: * usb_alloc_dev - usb device constructor (usbcore-internal)
630: * @parent: hub to which device is connected; null to allocate a root hub
631: * @bus: bus used to access the device
632: * @port1: one-based index of port; ignored for root hubs
633: *
634: * Context: task context, might sleep.
635: *
636: * Only hub drivers (including virtual root hub drivers for host
637: * controllers) should ever call this.
638: *
639: * This call may not be used in a non-sleeping context.
640: *
641: * Return: On success, a pointer to the allocated usb device. %NULL on
642: * failure.
643: */
644: struct usb_device *usb_alloc_dev(struct usb_device *parent,
645: struct usb_bus *bus, unsigned port1)
646: {
647: struct usb_device *dev;
648: struct usb_hcd *usb_hcd = bus_to_hcd(bus);
649: unsigned raw_port = port1;
650:
651: dev = kzalloc_obj(*dev);
652: if (!dev)
653: return NULL;
654:
655: if (!usb_get_hcd(usb_hcd)) {
656: kfree(dev);
657: return NULL;
658: }
659: /* Root hubs aren't true devices, so don't allocate HCD resources */
660: if (usb_hcd->driver->alloc_dev && parent &&
661: !usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
662: usb_put_hcd(bus_to_hcd(bus));
663: kfree(dev);
664: return NULL;
665: }
666:
667: device_initialize(&dev->dev);
668: dev->dev.bus = &usb_bus_type;
669: dev->dev.type = &usb_device_type;
670: dev->dev.groups = usb_device_groups;
671: set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
672: dev->state = USB_STATE_ATTACHED;
673: dev->lpm_disable_count = 1;
674: spin_lock_init(&dev->offload_lock);
675: dev->offload_usage = 0;
676: atomic_set(&dev->urbnum, 0);
677:
678: INIT_LIST_HEAD(&dev->ep0.urb_list);
679: dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
680: dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
681: /* ep0 maxpacket comes later, from device descriptor */
682: usb_enable_endpoint(dev, &dev->ep0, false);
683: dev->can_submit = 1;
684:
685: /* Save readable and stable topology id, distinguishing devices
686: * by location for diagnostics, tools, driver model, etc. The
687: * string is a path along hub ports, from the root. Each device's
688: * dev->devpath will be stable until USB is re-cabled, and hubs
689: * are often labeled with these port numbers. The name isn't
690: * as stable: bus->busnum changes easily from modprobe order,
691: * cardbus or pci hotplugging, and so on.
692: */
693: if (unlikely(!parent)) {
694: dev->devpath[0] = '0';
695: dev->route = 0;
696:
697: dev->dev.parent = bus->controller;
698: device_set_of_node_from_dev(&dev->dev, bus->sysdev);
699: dev_set_name(&dev->dev, "usb%d", bus->busnum);
700: } else {
701: int n;
702:
703: /* match any labeling on the hubs; it's one-based */
704: if (parent->devpath[0] == '0') {
705: n = snprintf(dev->devpath, sizeof(dev->devpath), "%d", port1);
706: /* Root ports are not counted in route string */
707: dev->route = 0;
708: } else {
709: n = snprintf(dev->devpath, sizeof(dev->devpath), "%s.%d",
710: parent->devpath, port1);
711: /* Route string assumes hubs have less than 16 ports */
712: if (port1 < 15)
713: dev->route = parent->route +
714: (port1 << ((parent->level - 1)*4));
715: else
716: dev->route = parent->route +
717: (15 << ((parent->level - 1)*4));
718: }
719: if (n >= sizeof(dev->devpath)) {
720: usb_put_hcd(bus_to_hcd(bus));
721: usb_put_dev(dev);
722: return NULL;
723: }
724:
725: dev->dev.parent = &parent->dev;
726: dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
727:
728: if (!parent->parent) {
729: /* device under root hub's port */
730: raw_port = usb_hcd_find_raw_port_number(usb_hcd,
731: port1);
732: }
733: dev->dev.of_node = usb_of_get_device_node(parent, raw_port);
734:
735: /* hub driver sets up TT records */
736: }
737:
738: dev->portnum = port1;
739: dev->bus = bus;
740: dev->parent = parent;
741: INIT_LIST_HEAD(&dev->filelist);
742:
743: #ifdef CONFIG_PM
744: pm_runtime_set_autosuspend_delay(&dev->dev,
745: usb_autosuspend_delay * 1000);
746: dev->connect_time = jiffies;
747: dev->active_duration = -jiffies;
748: #endif
749:
750: dev->authorized = usb_dev_authorized(dev, usb_hcd);
751: trace_usb_alloc_dev(dev);
752: return dev;
753: }
SourceFile:drivers/usb/core/usb.c]
|
| 45/2 |
2026/07/30 12:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 50252
output: 36
thoughts: 458
Thoughts: **Analyzing the KASAN Report and USB/I2C Device Relationships**
Okay, let's break this down. The KASAN report is definitely pointing at an issue involving a `struct usb_device` object freed from `kmalloc-4k`. That makes sense; `usb_alloc_dev` uses `kzalloc_obj`, and a `usb_device` is 2251 bytes, fitting neatly into that 4k slab. So far, so good.
Now, the interesting part: the suspicion that an `i2c_adapter` is somehow getting registered with the `usb_device` as its parent. That's immediately a red flag. Typically, in the USB subsystem, the `usb_device` is the parent of the `usb_interface`, and drivers bind to the *interface* not the device itself. Consequently, the `i2c_adapter`'s parent *should* be `usb_interface->dev`, right? `usb_interface` is allocated via `kzalloc_obj` in functions like `usb_ifnum_to_if` or `usb_set_configuration`, and its size of 1672 bytes would put it in `kmalloc-2k`.
But the KASAN report says the freed object is in `kmalloc-4k`, strongly suggesting we're dealing with the `usb_device` itself. The offset of the `parent` pointer (176 bytes) *within* the reported object confirms that the `parent` *cannot* be the `usb_interface`. Its `dev` member is at offset 120, so `usb_interface` is *not* the parent. It has to be `usb_device`. That is the crux of the issue.
So, how is this happening? Are there any I2C adapters *actually* registered directly with a `usb_device` as the parent? Let's check the code: Specifically, let's search for calls to `i2c_add_adapter` where `adapter->dev.parent` is directly set to `usb_device->dev`. It's possible an I2C adapter is registered by a driver that *does* bind to the `usb_device` instead of an interface. Granted, that's unusual β `usb_generic_driver` is an example of a `usb_device` driver, but it doesn't usually register I2C adapters, as far as I know.
Time to search through `drivers/media/usb/` and `drivers/usb/` for instances where `dev.parent = &usb_dev->dev` or a similar pattern is being used. That should shed some light on this, and hopefully explain the KASAN report.
|
| 46/2 |
2026/07/30 12:20 |
tool |
grepper |
0m
Args: map[Expression:\.dev\.parent = .*&.*->dev PathPrefix:drivers/media/usb/]
Results: map[Output:drivers/media/usb/au0828/au0828-i2c.c=354=int au0828_i2c_register(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-i2c.c-361-
drivers/media/usb/au0828/au0828-i2c.c:362: dev->i2c_adap.dev.parent = &dev->usbdev->dev;
drivers/media/usb/au0828/au0828-i2c.c-363-
--
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c=56=static int dvb_usbv2_i2c_init(struct dvb_usb_device *d)
--
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c-65- d->i2c_adap.algo = d->props->i2c_algo;
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c:66: d->i2c_adap.dev.parent = &d->udev->dev;
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c-67- i2c_set_adapdata(&d->i2c_adap, d);
--
drivers/media/usb/dvb-usb/dvb-usb-i2c.c=11=int dvb_usb_i2c_init(struct dvb_usb_device *d)
--
drivers/media/usb/dvb-usb/dvb-usb-i2c.c-26- d->i2c_adap.algo_data = NULL;
drivers/media/usb/dvb-usb/dvb-usb-i2c.c:27: d->i2c_adap.dev.parent = &d->udev->dev;
drivers/media/usb/dvb-usb/dvb-usb-i2c.c-28-
--
drivers/media/usb/em28xx/em28xx-i2c.c=970=int em28xx_i2c_register(struct em28xx *dev, unsigned int bus,
--
drivers/media/usb/em28xx/em28xx-i2c.c-982- dev->i2c_adap[bus] = em28xx_adap_template;
drivers/media/usb/em28xx/em28xx-i2c.c:983: dev->i2c_adap[bus].dev.parent = &dev->intf->dev;
drivers/media/usb/em28xx/em28xx-i2c.c-984- strscpy(dev->i2c_adap[bus].name, dev_name(&dev->intf->dev),
--
drivers/media/usb/hdpvr/hdpvr-i2c.c=180=int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
--
drivers/media/usb/hdpvr/hdpvr-i2c.c-184- dev->i2c_adapter = hdpvr_i2c_adapter_template;
drivers/media/usb/hdpvr/hdpvr-i2c.c:185: dev->i2c_adapter.dev.parent = &dev->udev->dev;
drivers/media/usb/hdpvr/hdpvr-i2c.c-186-
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c=591=void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-622- strscpy(hdw->i2c_adap.name, hdw->name, sizeof(hdw->i2c_adap.name));
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c:623: hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-624- hdw->i2c_adap.algo = &hdw->i2c_algo;
]
|
| 47/2 |
2026/07/30 12:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 52470
output: 26
thoughts: 381
Thoughts: **Analyzing I2C Adapter Parent References in USB Drivers**
Okay, let's break this down. It seems a pattern is emerging with these USB drivers. I'm seeing that drivers like `dvb_usb_device`, `au0828`, `hdpvr`, and `pvrusb2` are all setting the `i2c_adap.dev.parent` field to the `usb_device->dev` structure. That's the key connection.
Now, the interesting part is what happens during disconnect. The driver's `disconnect` function gets called when the USB device is removed, which makes sense. Then the driver unregisters the I2C adapter, using functions like `i2c_del_adapter`. This is where it gets critical. `i2c_del_adapter` calls `device_unregister(&adap->dev)`. This should *drop* the reference that `adap->dev.parent` (which, again, points to the USB device's `dev` structure) has to its parent. Crucially, the USB device is then freed.
However, if an application still has the I2C adapter open via a `/dev/i2c-X` device node, `i2c_get_adapter` *holds* a reference to `adap->dev`. That means the `i2c_adapter` itself *isn't* automatically freed because the system thinks something is still using it.
But...wait a second. If the `i2c_adapter` struct is embedded *within* the driver's private struct (like `struct dvb_usb_device` or something similar), and the driver then frees *that* struct during the `disconnect` process, the `i2c_adapter` would get freed along with everything else! That's the likely scenario.
So, I need to check how `dvb_usb_device` handles this. The question is, does it free its private struct in `disconnect`, including the embedded `i2c_adapter`? I need to verify that.
|
| 48/2 |
2026/07/30 12:20 |
tool |
codesearch-definition-source |
0m
Args: map[Name:dvb_usb_device_exit]
Results: map[SourceCode: 329: void dvb_usb_device_exit(struct usb_interface *intf)
330: {
331: struct dvb_usb_device *d = usb_get_intfdata(intf);
332: const char *default_name = "generic DVB-USB module";
333: char name[40];
334:
335: usb_set_intfdata(intf, NULL);
336: if (d != NULL && d->desc != NULL) {
337: strscpy(name, d->desc->name, sizeof(name));
338: dvb_usb_exit(d);
339: } else {
340: strscpy(name, default_name, sizeof(name));
341: }
342: info("%s successfully deinitialized and disconnected.", name);
343:
344: }
SourceFile:drivers/media/usb/dvb-usb/dvb-usb-init.c]
|
| 49/2 |
2026/07/30 12:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 53611
output: 24
thoughts: 12
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Examining the `dvb_usb_exit` Function**
Okay, so I'm thinking about the DVB USB driver framework, and the crucial `dvb_usb_exit` function in particular. My mind immediately jumps to that function as the cleanup and teardown point. I need to make sure I understand its execution path and all its implications. I'm focusing on ensuring it handles resources correctly, avoids memory leaks, and doesn't leave the system in an unstable state. My checklist in my head includes things like: are the USB endpoints properly de-registered? Is the associated DVB device freed, and is it done in the correct order to avoid race conditions with other modules? I'm visualizing the code flow now - where are the critical mutexes, what locks are held, what dependencies exist on the driver's state. I need to be sure any allocated buffers are freed, DMA mappings are unmapped if used, and the USB device itself is properly detached. Let's dig in and review `dvb_usb_exit` with a critical eye, checking for the usual suspects: potential double-frees, incorrect resource release order, and thread-safety issues. Gotta make sure it's robust and handles all the edge cases.
|
| 50/2 |
2026/07/30 12:20 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 138: /* general initialization functions */
139: static int dvb_usb_exit(struct dvb_usb_device *d)
140: {
141: deb_info("state before exiting everything: %x\n", d->state);
142: dvb_usb_remote_exit(d);
143: dvb_usb_adapter_exit(d);
144: dvb_usb_i2c_exit(d);
145: deb_info("state should be zero now: %x\n", d->state);
146: d->state = DVB_USB_STATE_INIT;
147:
148: if (d->priv != NULL && d->props.priv_destroy != NULL)
149: d->props.priv_destroy(d);
150:
151: kfree(d->priv);
152: kfree(d);
153: return 0;
154: }
SourceFile:drivers/media/usb/dvb-usb/dvb-usb-init.c]
|
| 51/2 |
2026/07/30 12:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 54241
output: 31
thoughts: 1689
Thoughts: **Analyzing a Use-After-Free Vulnerability**
Okay, so here's what's running through my head. We have a Use-After-Free (UAF) situation, and I'm trying to pinpoint the root cause. My initial thought was that `dvb_usb_exit` might be the culprit, freeing a structure (`d`) that includes an I2C adapter (`d->i2c_adap`), leading to a UAF when the adapter is still referenced. But the KASAN report throws a curveball: the UAF isn't on `dvb_usb_device` itself, but on `usb_device`. That's strange.
First, I need to understand this discrepancy. If the device's main struct `d` is freed, its internal `i2c_adap` should *also* be freed, so the fact that we're getting a report on the USB device itself feels strange. The KASAN report shows the buggy address is 264 bytes inside a 4096-byte region, but `usb_device` is 2251 bytes, within a `kmalloc-4k` region, not a `kmalloc-16k` region which makes no sense. The original UAF hypothesis doesn't seem to hold because the structure is not big enough.
So, let's trace the allocation. The KASAN report's stack trace points to `drivers/usb/mon/mon_main.c` and specifically to the allocation of a USB device. But then I realize: this stack trace is *for the page* allocation, not the object itself. It's the SLAB PAGE that's being described. The *object* was allocated by `nsim_dev_trap_skb_build` as `skb->head`.
This clicks. The KASAN report is showing the *last* allocation and free of that memory, which, in this case, is `skb->head` allocated and freed by `netdevsim`. The initial allocation of `usb_device` is lost from the KASAN report because it only keeps the last alloc/free. The memory was reused.
Now, if `usb_device` was allocated and freed, and then reallocated as `skb->head`, it's not clear where the original problem occurred. I need to understand the relationship between the `usb_device` and the `skb->head`.
Let's do some math: If the `usb_device` was allocated at `ffff8880270b4000`, the `usb_device->dev` is at offset 176. The `parent` pointer points to `ffff8880270b40b0`. It makes perfect sense! So the same memory was reallocated as `skb->head`!
Here's the likely scenario:
1. A USB device is created.
2. A driver binds to it and registers an I2C adapter with `adapter->dev.parent = &usb_device->dev`. This is where the initial relationship is established.
3. The I2C adapter is opened via `/dev/i2c-X`.
4. The USB device is disconnected.
5. The driver unregisters the I2C adapter.
6. *Crucially, the driver is freeing its private structure.*
Here's where it gets interesting and I need to verify assumptions. If the driver frees its private struct (let's call it `d` again), the I2C adapter `i2c_adapter` within it should be freed! But if that happens, there would be a UAF when `i2c_adapter_lock_bus` accesses `adapter->bus_lock`.
Wait a second: if `i2c_adapter` *is* freed, then a KASAN report would be triggered on the access of the `i2c_adapter->bus_lock` field. The KASAN report, however, says the UAF is on `parent->type`, which is *inside* `usb_device` which is `i2c_adapter->dev.parent->type`! This means `i2c_adapter` itself IS NOT FREED! This also means the memory is *not* reallocated as `skb->head`.
So, how can `i2c_adapter` not be freed? Either it's dynamically allocated separately, or, more likely, the driver uses something like `devm_kzalloc`, tying the I2C adapter's lifetime to `usb_interface->dev`. So when the `usb_interface` is destroyed, the I2C adapter goes with it. The `usb_device` is
|
| 52/2 |
2026/07/30 12:20 |
tool |
grepper |
0m
Args: map[Expression:i2c_adapter PathPrefix:drivers/media/usb/]
Results: map[Output:
Full output is too long, showing 500 out of 1286 lines.
Use more precise expression if possible.
drivers/media/usb/au0828/au0828-i2c.c=21=MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
--
drivers/media/usb/au0828/au0828-i2c.c-25-
drivers/media/usb/au0828/au0828-i2c.c:26:static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
drivers/media/usb/au0828/au0828-i2c.c-27-{
--
drivers/media/usb/au0828/au0828-i2c.c-32-
drivers/media/usb/au0828/au0828-i2c.c:33:static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
drivers/media/usb/au0828/au0828-i2c.c-34-{
--
drivers/media/usb/au0828/au0828-i2c.c-48-
drivers/media/usb/au0828/au0828-i2c.c:49:static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
drivers/media/usb/au0828/au0828-i2c.c-50-{
--
drivers/media/usb/au0828/au0828-i2c.c-55-
drivers/media/usb/au0828/au0828-i2c.c:56:static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
drivers/media/usb/au0828/au0828-i2c.c-57-{
--
drivers/media/usb/au0828/au0828-i2c.c-71-
drivers/media/usb/au0828/au0828-i2c.c:72:static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
drivers/media/usb/au0828/au0828-i2c.c-73-{
--
drivers/media/usb/au0828/au0828-i2c.c-78-
drivers/media/usb/au0828/au0828-i2c.c:79:static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
drivers/media/usb/au0828/au0828-i2c.c-80-{
--
drivers/media/usb/au0828/au0828-i2c.c-94-
drivers/media/usb/au0828/au0828-i2c.c:95:static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
drivers/media/usb/au0828/au0828-i2c.c-96-{
--
drivers/media/usb/au0828/au0828-i2c.c-101-
drivers/media/usb/au0828/au0828-i2c.c:102:static int i2c_wait_done(struct i2c_adapter *i2c_adap)
drivers/media/usb/au0828/au0828-i2c.c-103-{
--
drivers/media/usb/au0828/au0828-i2c.c-118-/* FIXME: Implement join handling correctly */
drivers/media/usb/au0828/au0828-i2c.c:119:static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
drivers/media/usb/au0828/au0828-i2c.c-120- const struct i2c_msg *msg, int joined_rlen)
--
drivers/media/usb/au0828/au0828-i2c.c-208-/* FIXME: Implement join handling correctly */
drivers/media/usb/au0828/au0828-i2c.c:209:static int i2c_readbytes(struct i2c_adapter *i2c_adap,
drivers/media/usb/au0828/au0828-i2c.c-210- const struct i2c_msg *msg, int joined)
--
drivers/media/usb/au0828/au0828-i2c.c-274-
drivers/media/usb/au0828/au0828-i2c.c:275:static int i2c_xfer(struct i2c_adapter *i2c_adap,
drivers/media/usb/au0828/au0828-i2c.c-276- struct i2c_msg *msgs, int num)
--
drivers/media/usb/au0828/au0828-i2c.c-309-
drivers/media/usb/au0828/au0828-i2c.c:310:static u32 au0828_functionality(struct i2c_adapter *adap)
drivers/media/usb/au0828/au0828-i2c.c-311-{
--
drivers/media/usb/au0828/au0828-i2c.c=315=static const struct i2c_algorithm au0828_i2c_algo_template = {
--
drivers/media/usb/au0828/au0828-i2c.c-321-
drivers/media/usb/au0828/au0828-i2c.c:322:static const struct i2c_adapter au0828_i2c_adap_template = {
drivers/media/usb/au0828/au0828-i2c.c-323- .name = KBUILD_MODNAME,
--
drivers/media/usb/au0828/au0828.h=173=struct au0828_dev {
--
drivers/media/usb/au0828/au0828.h-180- /* I2C */
drivers/media/usb/au0828/au0828.h:181: struct i2c_adapter i2c_adap;
drivers/media/usb/au0828/au0828.h-182- struct i2c_algorithm i2c_algo;
--
drivers/media/usb/b2c2/flexcop-usb.c=220=static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
--
drivers/media/usb/b2c2/flexcop-usb.c-227-/* usb i2c stuff */
drivers/media/usb/b2c2/flexcop-usb.c:228:static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
drivers/media/usb/b2c2/flexcop-usb.c-229- flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
--
drivers/media/usb/b2c2/flexcop-usb.c=309=static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
--
drivers/media/usb/b2c2/flexcop-usb.c-314-
drivers/media/usb/b2c2/flexcop-usb.c:315:static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
drivers/media/usb/b2c2/flexcop-usb.c-316- flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
--
drivers/media/usb/cx231xx/cx231xx-cards.c=1250=void cx231xx_card_setup(struct cx231xx *dev)
--
drivers/media/usb/cx231xx/cx231xx-cards.c-1272- if (dev->board.tuner_type != TUNER_ABSENT) {
drivers/media/usb/cx231xx/cx231xx-cards.c:1273: struct i2c_adapter *tuner_i2c = cx231xx_get_i2c_adap(dev,
drivers/media/usb/cx231xx/cx231xx-cards.c-1274- dev->board.tuner_i2c_master);
--
drivers/media/usb/cx231xx/cx231xx-dvb.c=616=static int dvb_init(struct cx231xx *dev)
--
drivers/media/usb/cx231xx/cx231xx-dvb.c-619- struct cx231xx_dvb *dvb;
drivers/media/usb/cx231xx/cx231xx-dvb.c:620: struct i2c_adapter *tuner_i2c;
drivers/media/usb/cx231xx/cx231xx-dvb.c:621: struct i2c_adapter *demod_i2c;
drivers/media/usb/cx231xx/cx231xx-dvb.c-622- struct i2c_client *client;
drivers/media/usb/cx231xx/cx231xx-dvb.c:623: struct i2c_adapter *adapter;
drivers/media/usb/cx231xx/cx231xx-dvb.c-624-
--
drivers/media/usb/cx231xx/cx231xx-dvb.c-747- "%s: looking for tuner / demod on i2c bus: %d\n",
drivers/media/usb/cx231xx/cx231xx-dvb.c:748: __func__, i2c_adapter_id(tuner_i2c));
drivers/media/usb/cx231xx/cx231xx-dvb.c-749-
--
drivers/media/usb/cx231xx/cx231xx-dvb.c-852- lgdt3306a_config.fe = &dev->dvb->frontend[0];
drivers/media/usb/cx231xx/cx231xx-dvb.c:853: lgdt3306a_config.i2c_adapter = &adapter;
drivers/media/usb/cx231xx/cx231xx-dvb.c-854-
--
drivers/media/usb/cx231xx/cx231xx-dvb.c-895- "%s: looking for demod on i2c bus: %d\n",
drivers/media/usb/cx231xx/cx231xx-dvb.c:896: __func__, i2c_adapter_id(tuner_i2c));
drivers/media/usb/cx231xx/cx231xx-dvb.c-897-
--
drivers/media/usb/cx231xx/cx231xx-dvb.c-924- si2168_config.fe = &dev->dvb->frontend[0];
drivers/media/usb/cx231xx/cx231xx-dvb.c:925: si2168_config.i2c_adapter = &adapter;
drivers/media/usb/cx231xx/cx231xx-dvb.c-926- si2168_config.ts_clock_inv = true;
--
drivers/media/usb/cx231xx/cx231xx-dvb.c-993- si2168_config.fe = &dev->dvb->frontend[0];
drivers/media/usb/cx231xx/cx231xx-dvb.c:994: si2168_config.i2c_adapter = &adapter;
drivers/media/usb/cx231xx/cx231xx-dvb.c-995- si2168_config.ts_clock_inv = true;
--
drivers/media/usb/cx231xx/cx231xx-dvb.c-1032- {
drivers/media/usb/cx231xx/cx231xx-dvb.c:1033: struct i2c_adapter *adapter2;
drivers/media/usb/cx231xx/cx231xx-dvb.c-1034- struct si2157_config si2157_config = {};
--
drivers/media/usb/cx231xx/cx231xx-dvb.c-1040- lgdt3306a_config.fe = &dev->dvb->frontend[0];
drivers/media/usb/cx231xx/cx231xx-dvb.c:1041: lgdt3306a_config.i2c_adapter = &adapter;
drivers/media/usb/cx231xx/cx231xx-dvb.c-1042-
--
drivers/media/usb/cx231xx/cx231xx-dvb.c-1055- si2168_config.fe = &dev->dvb->frontend[1];
drivers/media/usb/cx231xx/cx231xx-dvb.c:1056: si2168_config.i2c_adapter = &adapter2;
drivers/media/usb/cx231xx/cx231xx-dvb.c-1057- si2168_config.ts_clock_inv = true;
--
drivers/media/usb/cx231xx/cx231xx-i2c.c=52=static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus,
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-71- */
drivers/media/usb/cx231xx/cx231xx-i2c.c:72:static int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap,
drivers/media/usb/cx231xx/cx231xx-i2c.c-73- const struct i2c_msg *msg)
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-182- */
drivers/media/usb/cx231xx/cx231xx-i2c.c:183:static int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap,
drivers/media/usb/cx231xx/cx231xx-i2c.c-184- const struct i2c_msg *msg)
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-268- */
drivers/media/usb/cx231xx/cx231xx-i2c.c:269:static int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap,
drivers/media/usb/cx231xx/cx231xx-i2c.c-270- const struct i2c_msg *msg1,
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-332- */
drivers/media/usb/cx231xx/cx231xx-i2c.c:333:static int cx231xx_i2c_check_for_device(struct i2c_adapter *i2c_adap,
drivers/media/usb/cx231xx/cx231xx-i2c.c-334- const struct i2c_msg *msg)
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-359- */
drivers/media/usb/cx231xx/cx231xx-i2c.c:360:static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
drivers/media/usb/cx231xx/cx231xx-i2c.c-361- struct i2c_msg msgs[], int num)
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-437- */
drivers/media/usb/cx231xx/cx231xx-i2c.c:438:static u32 functionality(struct i2c_adapter *adap)
drivers/media/usb/cx231xx/cx231xx-i2c.c-439-{
--
drivers/media/usb/cx231xx/cx231xx-i2c.c=443=static const struct i2c_algorithm cx231xx_algo = {
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-447-
drivers/media/usb/cx231xx/cx231xx-i2c.c:448:static const struct i2c_adapter cx231xx_adap_template = {
drivers/media/usb/cx231xx/cx231xx-i2c.c-449- .owner = THIS_MODULE,
--
drivers/media/usb/cx231xx/cx231xx-i2c.c=476=void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port)
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-479- int i, rc;
drivers/media/usb/cx231xx/cx231xx-i2c.c:480: struct i2c_adapter *adap;
drivers/media/usb/cx231xx/cx231xx-i2c.c-481- struct i2c_msg msg = {
--
drivers/media/usb/cx231xx/cx231xx-i2c.c=573=void cx231xx_i2c_mux_unregister(struct cx231xx *dev)
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-577-
drivers/media/usb/cx231xx/cx231xx-i2c.c:578:struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port)
drivers/media/usb/cx231xx/cx231xx-i2c.c-579-{
--
drivers/media/usb/cx231xx/cx231xx.h=446=struct cx231xx_i2c {
--
drivers/media/usb/cx231xx/cx231xx.h-451- /* i2c i/o */
drivers/media/usb/cx231xx/cx231xx.h:452: struct i2c_adapter i2c_adap;
drivers/media/usb/cx231xx/cx231xx.h-453- int i2c_rc;
--
drivers/media/usb/cx231xx/cx231xx.h=562=struct cx231xx {
--
drivers/media/usb/cx231xx/cx231xx.h-601- struct i2c_mux_core *muxc;
drivers/media/usb/cx231xx/cx231xx.h:602: struct i2c_adapter *i2c_mux_adap[2];
drivers/media/usb/cx231xx/cx231xx.h-603-
--
drivers/media/usb/cx231xx/cx231xx.h=745=void cx231xx_i2c_mux_unregister(struct cx231xx *dev);
drivers/media/usb/cx231xx/cx231xx.h:746:struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port);
drivers/media/usb/cx231xx/cx231xx.h-747-
--
drivers/media/usb/dvb-usb-v2/af9015.c=126=static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
--
drivers/media/usb/dvb-usb-v2/af9015.c-138-
drivers/media/usb/dvb-usb-v2/af9015.c:139:static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
drivers/media/usb/dvb-usb-v2/af9015.c-140- int num)
--
drivers/media/usb/dvb-usb-v2/af9015.c-257-
drivers/media/usb/dvb-usb-v2/af9015.c:258:static u32 af9015_i2c_func(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/af9015.c-259-{
--
drivers/media/usb/dvb-usb-v2/af9015.c=998=static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/af9015.c-1003- struct i2c_client *client;
drivers/media/usb/dvb-usb-v2/af9015.c:1004: struct i2c_adapter *adapter;
drivers/media/usb/dvb-usb-v2/af9015.c-1005- int ret;
--
drivers/media/usb/dvb-usb-v2/af9015.c-1009- client = state->demod_i2c_client[adap->id];
drivers/media/usb/dvb-usb-v2/af9015.c:1010: adapter = state->af9013_pdata[adap->id].get_i2c_adapter(client);
drivers/media/usb/dvb-usb-v2/af9015.c-1011-
--
drivers/media/usb/dvb-usb-v2/af9035.c=180=static int af9035_add_i2c_dev(struct dvb_usb_device *d, const char *type,
drivers/media/usb/dvb-usb-v2/af9035.c:181: u8 addr, void *platform_data, struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/af9035.c-182-{
--
drivers/media/usb/dvb-usb-v2/af9035.c=232=static void af9035_del_i2c_dev(struct dvb_usb_device *d)
--
drivers/media/usb/dvb-usb-v2/af9035.c-266-
drivers/media/usb/dvb-usb-v2/af9035.c:267:static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
drivers/media/usb/dvb-usb-v2/af9035.c-268- struct i2c_msg msg[], int num)
--
drivers/media/usb/dvb-usb-v2/af9035.c-480-
drivers/media/usb/dvb-usb-v2/af9035.c:481:static u32 af9035_i2c_functionality(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/af9035.c-482-{
--
drivers/media/usb/dvb-usb-v2/af9035.c=1150=static int af9035_frontend_callback(void *adapter_priv, int component,
--
drivers/media/usb/dvb-usb-v2/af9035.c-1152-{
drivers/media/usb/dvb-usb-v2/af9035.c:1153: struct i2c_adapter *adap = adapter_priv;
drivers/media/usb/dvb-usb-v2/af9035.c-1154- struct dvb_usb_device *d = i2c_get_adapdata(adap);
--
drivers/media/usb/dvb-usb-v2/af9035.c=1225=static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/af9035.c-1231- struct si2168_config si2168_config;
drivers/media/usb/dvb-usb-v2/af9035.c:1232: struct i2c_adapter *adapter;
drivers/media/usb/dvb-usb-v2/af9035.c-1233-
--
drivers/media/usb/dvb-usb-v2/af9035.c-1278- memset(&si2168_config, 0, sizeof(si2168_config));
drivers/media/usb/dvb-usb-v2/af9035.c:1279: si2168_config.i2c_adapter = &adapter;
drivers/media/usb/dvb-usb-v2/af9035.c-1280- si2168_config.fe = &adap->fe[0];
--
drivers/media/usb/dvb-usb-v2/af9035.c-1294- }
drivers/media/usb/dvb-usb-v2/af9035.c:1295: state->i2c_adapter_demod = adapter;
drivers/media/usb/dvb-usb-v2/af9035.c-1296-
--
drivers/media/usb/dvb-usb-v2/af9035.c=1626=static int it930x_tuner_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/af9035.c-1661- it930x_addresses_table[state->it930x_addresses].tuner_i2c_addr,
drivers/media/usb/dvb-usb-v2/af9035.c:1662: &si2157_config, state->i2c_adapter_demod);
drivers/media/usb/dvb-usb-v2/af9035.c-1663- if (ret)
--
drivers/media/usb/dvb-usb-v2/af9035.h=45=struct state {
--
drivers/media/usb/dvb-usb-v2/af9035.h-63- struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX];
drivers/media/usb/dvb-usb-v2/af9035.h:64: struct i2c_adapter *i2c_adapter_demod;
drivers/media/usb/dvb-usb-v2/af9035.h-65- struct platform_device *platform_device_tuner[2];
--
drivers/media/usb/dvb-usb-v2/anysee.c=176=static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
--
drivers/media/usb/dvb-usb-v2/anysee.c-183-/* I2C */
drivers/media/usb/dvb-usb-v2/anysee.c:184:static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
drivers/media/usb/dvb-usb-v2/anysee.c-185- int num)
--
drivers/media/usb/dvb-usb-v2/anysee.c-232-
drivers/media/usb/dvb-usb-v2/anysee.c:233:static u32 anysee_i2c_func(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/anysee.c-234-{
--
drivers/media/usb/dvb-usb-v2/anysee.c=611=static int anysee_add_i2c_dev(struct dvb_usb_device *d, const char *type,
--
drivers/media/usb/dvb-usb-v2/anysee.c-616- struct i2c_client *client;
drivers/media/usb/dvb-usb-v2/anysee.c:617: struct i2c_adapter *adapter = &d->i2c_adap;
drivers/media/usb/dvb-usb-v2/anysee.c-618- struct i2c_board_info board_info = {
--
drivers/media/usb/dvb-usb-v2/au6610.c=66=static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
--
drivers/media/usb/dvb-usb-v2/au6610.c-82-/* I2C */
drivers/media/usb/dvb-usb-v2/au6610.c:83:static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
drivers/media/usb/dvb-usb-v2/au6610.c-84- int num)
--
drivers/media/usb/dvb-usb-v2/au6610.c-112-
drivers/media/usb/dvb-usb-v2/au6610.c:113:static u32 au6610_i2c_func(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/au6610.c-114-{
--
drivers/media/usb/dvb-usb-v2/az6007.c=689=static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
--
drivers/media/usb/dvb-usb-v2/az6007.c-742-/* I2C */
drivers/media/usb/dvb-usb-v2/az6007.c:743:static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
drivers/media/usb/dvb-usb-v2/az6007.c-744- int num)
--
drivers/media/usb/dvb-usb-v2/az6007.c-835-
drivers/media/usb/dvb-usb-v2/az6007.c:836:static u32 az6007_i2c_func(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/az6007.c-837-{
--
drivers/media/usb/dvb-usb-v2/ce6230.c=83=static struct zl10353_config ce6230_zl10353_config;
drivers/media/usb/dvb-usb-v2/ce6230.c-84-
drivers/media/usb/dvb-usb-v2/ce6230.c:85:static int ce6230_i2c_master_xfer(struct i2c_adapter *adap,
drivers/media/usb/dvb-usb-v2/ce6230.c-86- struct i2c_msg msg[], int num)
--
drivers/media/usb/dvb-usb-v2/ce6230.c-151-
drivers/media/usb/dvb-usb-v2/ce6230.c:152:static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/ce6230.c-153-{
--
drivers/media/usb/dvb-usb-v2/dvb_usb.h=375=struct dvb_usb_device {
--
drivers/media/usb/dvb-usb-v2/dvb_usb.h-389- struct mutex i2c_mutex;
drivers/media/usb/dvb-usb-v2/dvb_usb.h:390: struct i2c_adapter i2c_adap;
drivers/media/usb/dvb-usb-v2/dvb_usb.h-391-
--
drivers/media/usb/dvb-usb-v2/dvbsky.c=86=static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-98-/* I2C */
drivers/media/usb/dvb-usb-v2/dvbsky.c:99:static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
drivers/media/usb/dvb-usb-v2/dvbsky.c-100- int num)
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-166-
drivers/media/usb/dvb-usb-v2/dvbsky.c:167:static u32 dvbsky_i2c_func(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/dvbsky.c-168-{
--
drivers/media/usb/dvb-usb-v2/dvbsky.c=274=static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-277- struct dvb_usb_device *d = adap_to_d(adap);
drivers/media/usb/dvb-usb-v2/dvbsky.c:278: struct i2c_adapter *i2c_adapter;
drivers/media/usb/dvb-usb-v2/dvbsky.c-279- struct m88ds3103_platform_data m88ds3103_pdata = {};
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-299- adap->fe[0] = m88ds3103_pdata.get_dvb_frontend(state->i2c_client_demod);
drivers/media/usb/dvb-usb-v2/dvbsky.c:300: i2c_adapter = m88ds3103_pdata.get_i2c_adapter(state->i2c_client_demod);
drivers/media/usb/dvb-usb-v2/dvbsky.c-301-
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-306- state->i2c_client_tuner = dvb_module_probe("ts2020", NULL,
drivers/media/usb/dvb-usb-v2/dvbsky.c:307: i2c_adapter,
drivers/media/usb/dvb-usb-v2/dvbsky.c-308- 0x60, &ts2020_config);
--
drivers/media/usb/dvb-usb-v2/dvbsky.c=376=static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-379- struct dvb_usb_device *d = adap_to_d(adap);
drivers/media/usb/dvb-usb-v2/dvbsky.c:380: struct i2c_adapter *i2c_adapter;
drivers/media/usb/dvb-usb-v2/dvbsky.c-381- struct m88ds3103_platform_data m88ds3103_pdata = {};
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-402- adap->fe[0] = m88ds3103_pdata.get_dvb_frontend(state->i2c_client_demod);
drivers/media/usb/dvb-usb-v2/dvbsky.c:403: i2c_adapter = m88ds3103_pdata.get_i2c_adapter(state->i2c_client_demod);
drivers/media/usb/dvb-usb-v2/dvbsky.c-404-
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-409- state->i2c_client_tuner = dvb_module_probe("ts2020", NULL,
drivers/media/usb/dvb-usb-v2/dvbsky.c:410: i2c_adapter,
drivers/media/usb/dvb-usb-v2/dvbsky.c-411- 0x60, &ts2020_config);
--
drivers/media/usb/dvb-usb-v2/dvbsky.c=447=static int dvbsky_t680c_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-450- struct dvb_usb_device *d = adap_to_d(adap);
drivers/media/usb/dvb-usb-v2/dvbsky.c:451: struct i2c_adapter *i2c_adapter;
drivers/media/usb/dvb-usb-v2/dvbsky.c-452- struct si2168_config si2168_config = {};
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-456- /* attach demod */
drivers/media/usb/dvb-usb-v2/dvbsky.c:457: si2168_config.i2c_adapter = &i2c_adapter;
drivers/media/usb/dvb-usb-v2/dvbsky.c-458- si2168_config.fe = &adap->fe[0];
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-471- state->i2c_client_tuner = dvb_module_probe("si2157", NULL,
drivers/media/usb/dvb-usb-v2/dvbsky.c:472: i2c_adapter,
drivers/media/usb/dvb-usb-v2/dvbsky.c-473- 0x60, &si2157_config);
--
drivers/media/usb/dvb-usb-v2/dvbsky.c=497=static int dvbsky_t330_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-500- struct dvb_usb_device *d = adap_to_d(adap);
drivers/media/usb/dvb-usb-v2/dvbsky.c:501: struct i2c_adapter *i2c_adapter;
drivers/media/usb/dvb-usb-v2/dvbsky.c-502- struct si2168_config si2168_config = {};
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-505- /* attach demod */
drivers/media/usb/dvb-usb-v2/dvbsky.c:506: si2168_config.i2c_adapter = &i2c_adapter;
drivers/media/usb/dvb-usb-v2/dvbsky.c-507- si2168_config.fe = &adap->fe[0];
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-521- state->i2c_client_tuner = dvb_module_probe("si2157", NULL,
drivers/media/usb/dvb-usb-v2/dvbsky.c:522: i2c_adapter,
drivers/media/usb/dvb-usb-v2/dvbsky.c-523- 0x60, &si2157_config);
--
drivers/media/usb/dvb-usb-v2/dvbsky.c=532=static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-535- struct dvb_usb_device *d = adap_to_d(adap);
drivers/media/usb/dvb-usb-v2/dvbsky.c:536: struct i2c_adapter *i2c_adapter;
drivers/media/usb/dvb-usb-v2/dvbsky.c-537- struct si2168_config si2168_config = {};
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-540- /* attach demod */
drivers/media/usb/dvb-usb-v2/dvbsky.c:541: si2168_config.i2c_adapter = &i2c_adapter;
drivers/media/usb/dvb-usb-v2/dvbsky.c-542- si2168_config.fe = &adap->fe[0];
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-560- state->i2c_client_tuner = dvb_module_probe("si2157", NULL,
drivers/media/usb/dvb-usb-v2/dvbsky.c:561: i2c_adapter,
drivers/media/usb/dvb-usb-v2/dvbsky.c-562- 0x60,
--
drivers/media/usb/dvb-usb-v2/dvbsky.c-566- state->i2c_client_tuner = dvb_module_probe("si2157", "si2141",
drivers/media/usb/dvb-usb-v2/dvbsky.c:567: i2c_adapter,
drivers/media/usb/dvb-usb-v2/dvbsky.c-568- 0x60,
--
drivers/media/usb/dvb-usb-v2/ec168.c=99=static struct ec100_config ec168_ec100_config;
drivers/media/usb/dvb-usb-v2/ec168.c-100-
drivers/media/usb/dvb-usb-v2/ec168.c:101:static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
drivers/media/usb/dvb-usb-v2/ec168.c-102- int num)
--
drivers/media/usb/dvb-usb-v2/ec168.c-173-
drivers/media/usb/dvb-usb-v2/ec168.c:174:static u32 ec168_i2c_func(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/ec168.c-175-{
--
drivers/media/usb/dvb-usb-v2/gl861.c=17=struct gl861 {
--
drivers/media/usb/dvb-usb-v2/gl861.c-20-
drivers/media/usb/dvb-usb-v2/gl861.c:21: struct i2c_adapter *demod_sub_i2c;
drivers/media/usb/dvb-usb-v2/gl861.c-22- struct i2c_client *i2c_client_demod;
--
drivers/media/usb/dvb-usb-v2/gl861.c=81=static int gl861_short_write(struct dvb_usb_device *d, u8 addr, u8 reg, u8 val)
--
drivers/media/usb/dvb-usb-v2/gl861.c-86-
drivers/media/usb/dvb-usb-v2/gl861.c:87:static int gl861_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
drivers/media/usb/dvb-usb-v2/gl861.c-88- int num)
--
drivers/media/usb/dvb-usb-v2/gl861.c-159-
drivers/media/usb/dvb-usb-v2/gl861.c:160:static u32 gl861_i2c_functionality(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/gl861.c-161-{
--
drivers/media/usb/dvb-usb-v2/lmedm04.c=485=static int lme2510_msg(struct dvb_usb_device *d,
--
drivers/media/usb/dvb-usb-v2/lmedm04.c-494-
drivers/media/usb/dvb-usb-v2/lmedm04.c:495:static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
drivers/media/usb/dvb-usb-v2/lmedm04.c-496- int num)
--
drivers/media/usb/dvb-usb-v2/lmedm04.c-556-
drivers/media/usb/dvb-usb-v2/lmedm04.c:557:static u32 lme2510_i2c_func(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/lmedm04.c-558-{
--
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c=427=static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state,
--
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c-798-
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c:799:int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c-800- struct i2c_msg msg[], int num)
--
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h-12-
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h:13:int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h-14- struct i2c_msg msg[], int num);
--
drivers/media/usb/dvb-usb-v2/mxl111sf.c=871=static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/mxl111sf.c-908-
drivers/media/usb/dvb-usb-v2/mxl111sf.c:909:static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/mxl111sf.c-910-{
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c=118=static int rtl28xxu_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-138-/* I2C */
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:139:static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-140- int num)
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-287-
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:288:static u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter)
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-289-{
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c=699=static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-744- adap->fe[0] = pdata->get_dvb_frontend(client);
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:745: dev->demod_i2c_adapter = pdata->get_i2c_adapter(client);
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-746-
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c=868=static int rtl2832u_frontend_callback(void *adapter_priv, int component,
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-870-{
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:871: struct i2c_adapter *adapter = adapter_priv;
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-872- struct device *parent = adapter->dev.parent;
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:873: struct i2c_adapter *parent_adapter;
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-874- struct dvb_usb_device *d;
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-882- */
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:883: if (parent != NULL && parent->type == &i2c_adapter_type)
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:884: parent_adapter = to_i2c_adapter(parent);
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-885- else
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c=907=static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-965- adap->fe[0] = pdata->get_dvb_frontend(client);
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:966: dev->demod_i2c_adapter = pdata->get_i2c_adapter(client);
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-967-
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1034- struct si2168_config si2168_config = {};
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:1035: struct i2c_adapter *adapter;
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1036-
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:1037: si2168_config.i2c_adapter = &adapter;
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1038- si2168_config.fe = &adap->fe[1];
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c=1137=static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1148- fe = dvb_attach(qt1010_attach, adap->fe[0],
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:1149: dev->demod_i2c_adapter,
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1150- &rtl28xxu_qt1010_config);
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1153- fe = dvb_attach(mt2060_attach, adap->fe[0],
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:1154: dev->demod_i2c_adapter,
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1155- &rtl28xxu_mt2060_config, 1220);
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1158- fe = dvb_attach(mxl5005s_attach, adap->fe[0],
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:1159: dev->demod_i2c_adapter,
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1160- &rtl28xxu_mxl5005s_config);
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c=1197=static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1216- fe = dvb_attach(fc0012_attach, adap->fe[0],
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:1217: dev->demod_i2c_adapter, &rtl2832u_fc0012_config);
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1218-
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1225- fe = dvb_attach(fc0013_attach, adap->fe[0],
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:1226: dev->demod_i2c_adapter, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1227-
--
drivers/media/usb/dvb-usb-v2/rtl28xxu.c-1242- request_module(info.type);
drivers/media/usb/dvb-usb-v2/rtl28xxu.c:1243: client = i2c_new_client_device(dev->demod_i2c_adapter,
]
|
| 53/2 |
2026/07/30 12:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 72060
output: 26
thoughts: 41
Thoughts: Okay, here's my take on those thoughts, framed as my own internal monologue, with a **bolded header**:
**Digging into the DVB-USB Driver Disconnect Sequence**
Right, let me just parse this quickly. Hmm, the code flow here⦠it seems `dvb_usb_device_exit` is being called directly from within `dvb_usbv2_disconnect`? Interesting. I've seen that pattern before, but it always warrants a quick double-check, especially in a driver context. I need to make sure the resource management is exactly as I expect. Okay, let's pull up the definition of `dvb_usbv2_disconnect`. Time to see what's actually happening on the other end of that function call. Need to understand the order of operations here; make sure nothing's getting freed too early, or that we're properly cleaning up all allocated resources. Let's see...
|
| 54/2 |
2026/07/30 12:20 |
tool |
codesearch-definition-source |
0m
Args: map[Name:dvb_usbv2_disconnect]
Results: map[SourceCode:1007: void dvb_usbv2_disconnect(struct usb_interface *intf)
1008: {
1009: struct dvb_usb_device *d = usb_get_intfdata(intf);
1010: const char *devname = kstrdup(dev_name(&d->udev->dev), GFP_KERNEL);
1011: const char *drvname = d->name;
1012:
1013: dev_dbg(&d->udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
1014: intf->cur_altsetting->desc.bInterfaceNumber);
1015:
1016: if (d->props->exit)
1017: d->props->exit(d);
1018:
1019: dvb_usbv2_exit(d);
1020:
1021: if (d->props->disconnect)
1022: d->props->disconnect(d);
1023:
1024: kfree(d->priv);
1025: kfree(d);
1026:
1027: pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n",
1028: KBUILD_MODNAME, drvname, devname);
1029: kfree(devname);
1030: }
SourceFile:drivers/media/usb/dvb-usb-v2/dvb_usb_core.c]
|
| 55/2 |
2026/07/30 12:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 72744
output: 27
thoughts: 217
Thoughts: **Investigating a Suspected Use-After-Free Vulnerability**
Okay, so I'm looking at this `dvb_usbv2_disconnect` function and immediately something smells fishy. It calls `kfree(d)`. Right, so `d` is getting freed. But, and this is the problem, if `d` is freed, then `d->i2c_adap` also gets freed, right? We're talking about pointers here, so one frees the other.
But hold on a second⦠if `d->i2c_adap` *is* freed, then a later call to `i2c_adapter_lock_bus` would try to access `adapter->bus_lock`. That's at offset 40 of the `i2c_adapter` struct. And if `i2c_adapter` is *inside* `d`, and `d` has been freed, then KASAN *should* be screaming about a Use-After-Free on `d`, which, by the way, is `kmalloc-16k`. I'd expect the report to be complaining about that.
But here's the kicker: the KASAN report is telling me UAF on `usb_device`, which is `kmalloc-4k`. That means that `i2c_adapter` is *not* getting freed as part of `d`. This just isn't making sense. I need to figure out how `i2c_adapter` can survive the free of `d`! Is this even a `dvb_usb_v2` driver? I need to check the relevant drivers! Let's check `au0828`.
|
| 56/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:au0828_usb_disconnect]
Results: map[SourceCode: 163: static void au0828_usb_disconnect(struct usb_interface *interface)
164: {
165: struct au0828_dev *dev = usb_get_intfdata(interface);
166:
167: dprintk(1, "%s()\n", __func__);
168:
169: /* there is a small window after disconnect, before
170: dev->usbdev is NULL, for poll (e.g: IR) try to access
171: the device and fill the dmesg with error messages.
172: Set the status so poll routines can check and avoid
173: access after disconnect.
174: */
175: set_bit(DEV_DISCONNECTED, &dev->dev_state);
176:
177: au0828_rc_unregister(dev);
178: /* Digital TV */
179: au0828_dvb_unregister(dev);
180:
181: usb_set_intfdata(interface, NULL);
182: mutex_lock(&dev->mutex);
183: dev->usbdev = NULL;
184: mutex_unlock(&dev->mutex);
185: if (au0828_analog_unregister(dev)) {
186: /*
187: * No need to call au0828_usb_release() if V4L2 is enabled,
188: * as this is already called via au0828_usb_v4l2_release()
189: */
190: return;
191: }
192: au0828_usb_release(dev);
193: }
SourceFile:drivers/media/usb/au0828/au0828-core.c]
|
| 57/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 73884
output: 27
thoughts: 15
Thoughts: Okay, let's dive into this. Here's my take on those thoughts, as if they're my own:
**Analyzing `au0828_usb_release`**
Alright, time to get to it. My initial thought is to take a look at `au0828_usb_release`. Given my experience, I'm already mentally running through the typical USB release function workflow. I'm expecting to see resource deallocation β perhaps memory free operations, cleanup of internal data structures related to the USB device, and potentially calls to deregister the device from the USB bus if it's being disconnected. I'll be looking specifically for any potential race conditions or missed cleanup steps that could lead to memory leaks or other issues. I'll also be mentally mapping the function's place within the overall driver architecture. Let's dig in and see what's actually going on.
|
| 58/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:au0828_usb_release]
Results: map[SourceCode: 153: void au0828_usb_release(struct au0828_dev *dev)
154: {
155: au0828_unregister_media_device(dev);
156:
157: /* I2C */
158: au0828_i2c_unregister(dev);
159:
160: kfree(dev);
161: }
SourceFile:drivers/media/usb/au0828/au0828-core.c]
|
| 59/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 74286
output: 27
thoughts: 82
Thoughts: **My Immediate Concerns Regarding the `au0828_usb_release` Function**
Okay, so `au0828_usb_release` is calling `kfree(dev)`. That's standard cleanup, freeing the device structure. My primary worry, as always with memory management, is that subsequent freeing of `dev->i2c_adap` could result in a double free. I'll need to check the code that sets up `i2c_adap` and verify there aren't any potential race conditions or other issues lurking there.
Wait a minute... I remember seeing something about `au0828_analog_unregister(dev)` potentially returning 1 if V4L2 is enabled. That's a red flag! If `au0828_analog_unregister` returns this value, it *could* imply a conditional path where `dev` is still in use, or at least that some resources associated with it haven't been properly cleaned up. I need to dive into the implementation of `au0828_analog_unregister` right now and understand the circumstances under which it returns 1. This is a potential bug or a subtle design flaw that needs thorough investigation. The relationship between `au0828_usb_release` and `au0828_analog_unregister` looks crucial here.
|
| 60/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:au0828_analog_unregister]
Results: map[SourceCode: 920: /* ------------------------------------------------------------------
921: V4L2 interface
922: ------------------------------------------------------------------*/
923: /*
924: * au0828_analog_unregister
925: * unregister v4l2 devices
926: */
927: int au0828_analog_unregister(struct au0828_dev *dev)
928: {
929: dprintk(1, "au0828_analog_unregister called\n");
930:
931: /* No analog TV */
932: if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
933: return 0;
934:
935: mutex_lock(&au0828_sysfs_lock);
936: vb2_video_unregister_device(&dev->vdev);
937: vb2_video_unregister_device(&dev->vbi_dev);
938: mutex_unlock(&au0828_sysfs_lock);
939:
940: v4l2_device_disconnect(&dev->v4l2_dev);
941: v4l2_device_put(&dev->v4l2_dev);
942:
943: return 1;
944: }
SourceFile:drivers/media/usb/au0828/au0828-video.c]
|
| 61/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 75117
output: 32
thoughts: 97
Thoughts: Okay, here's my interpretation of this scenario, focusing on the release sequence of this device.
**Understanding the Device Release Mechanism**
Alright, so the crucial takeaway here is how this device's resources are freed. If the return value is 1, a specific release function, `au0828_usb_release`, *isn't* directly invoked. Instead, the driver leans on a different mechanism: `v4l2_device_put(&dev->v4l2_dev)`. This is a V4L2-centric approach, which is good. I need to keep in mind that this is a V4L2 device. The system uses reference counting for the `v4l2_device`. The important thing to understand is that it leverages the `v4l2_device` refcount to control the device lifetime.
When that reference count for the `v4l2_device` drops to zero, *then* the registered `release` callback associated with that `v4l2_device` is automatically executed. This is where I have to look carefully at `au0828_usb_v4l2_release`. This is where all the actual device-specific resource cleanup presumably happens. I need to make sure this is what I expect. I'll need to check if there is an issue with how the refcount is managed. I must analyze `au0828_usb_v4l2_release` to confirm that all resources are properly freed when the count hits zero.
|
| 62/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:au0828_usb_v4l2_release]
Results: map[SourceCode: 635: static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
636: {
637: struct au0828_dev *dev =
638: container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
639:
640: v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
641: v4l2_device_unregister(&dev->v4l2_dev);
642: au0828_usb_v4l2_media_release(dev);
643: au0828_usb_release(dev);
644: }
SourceFile:drivers/media/usb/au0828/au0828-video.c]
|
| 63/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 75831
output: 27
thoughts: 273
Thoughts: **My Analysis of a Potential USB Device Driver Vulnerability**
Okay, so I'm digging into this driver, specifically looking at how the `au0828_usb_release` function is handled. My concern is that `au0828_usb_release` gets triggered during the release of the `v4l2_device` structure. Here's the key thing: if a V4L2 device like `/dev/videoX` is kept open, `au0828_usb_release` *isn't* called. This means the `dev` pointer within the driver, and crucially, `dev->i2c_adap`, aren't freed. But the underlying `usb_device` *is* released. This is where it gets interesting.
So, picture this: I open `/dev/videoX`, artificially bumping the `v4l2_device`'s reference count. Then, I trigger a USB disconnect. The `usb_device` is now gone, freed by the system. But because `/dev/videoX` is still open, `au0828_dev` remains, so the `dev->i2c_adap` pointer is still valid... kind of.
Now, here's the kicker: I then try to access `dev->i2c_adap` through an I2C character device like `/dev/i2c-X`, or maybe it was already open. When the I2C adapter attempts to access its `adapter->dev.parent` pointer, which is supposed to point to the USB device, it's pointing to *freed memory*! That's it! That's the vulnerability I'm looking for! This is a classic use-after-free scenario.
The question then is, is this isolated to the `au0828` driver? I'd better expand this test to other drivers that deal with USB V4L2 devices. I'm going to check the `cx231xx` driver next.
|
| 64/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:cx231xx_usb_disconnect]
Results: map[SourceCode:1926: /*
1927: * cx231xx_usb_disconnect()
1928: * called when the device gets disconnected
1929: * video device will be unregistered on v4l2_close in case it is still open
1930: */
1931: static void cx231xx_usb_disconnect(struct usb_interface *interface)
1932: {
1933: struct cx231xx *dev;
1934:
1935: dev = usb_get_intfdata(interface);
1936: usb_set_intfdata(interface, NULL);
1937:
1938: if (!dev)
1939: return;
1940:
1941: if (!dev->udev)
1942: return;
1943:
1944: dev->state |= DEV_DISCONNECTED;
1945:
1946: flush_request_modules(dev);
1947:
1948: /* wait until all current v4l2 io is finished then deallocate
1949: resources */
1950: mutex_lock(&dev->lock);
1951:
1952: wake_up_interruptible_all(&dev->open);
1953:
1954: if (dev->users) {
1955: dev_warn(dev->dev,
1956: "device %s is open! Deregistration and memory deallocation are deferred on close.\n",
1957: video_device_node_name(&dev->vdev));
1958:
1959: /* Even having users, it is safe to remove the RC i2c driver */
1960: cx231xx_ir_exit(dev);
1961:
1962: if (dev->USE_ISO)
1963: cx231xx_uninit_isoc(dev);
1964: else
1965: cx231xx_uninit_bulk(dev);
1966: wake_up_interruptible(&dev->wait_frame);
1967: wake_up_interruptible(&dev->wait_stream);
1968: } else {
1969: }
1970:
1971: cx231xx_close_extension(dev);
1972:
1973: mutex_unlock(&dev->lock);
1974:
1975: if (!dev->users)
1976: cx231xx_release_resources(dev);
1977: }
SourceFile:drivers/media/usb/cx231xx/cx231xx-cards.c]
|
| 65/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 77316
output: 29
thoughts: 104
Thoughts: **Resource Leakage in cx231xx Driver: A Deep Dive**
Okay, so I'm looking at this `cx231xx` driver code, and alarm bells are starting to go off. I'm seeing a potential resource leak, and it hinges on the `dev->users` counter. If `dev->users` is greater than zero, meaning someone still has a handle on this device, the `cx231xx_release_resources` function *isn't* called. This is the critical point.
Now, if `cx231xx_release_resources` doesn't run, the `dev` structure itself *isn't* freed. And that's not all. Crucially, the `dev->i2c_adap` pointer, which represents the I2C adapter associated with this device, also remains untouched and unfreed! This means we are leaking memory associated with the I2C adapter.
But here is where it gets interesting...
I think there may be an even more fundamental issue: The `usb_device` structure is freed, irrespective. So the USB device is gone, but the cx231xx-related resources remain, potentially orphaned.
Now, I'm starting to wonder if the `cx231xx` driver, somewhere in its I2C initialization, might be setting the `adapter->dev.parent` to point to the USB device's device structure. Let me quickly double-check the `cx231xx_i2c_register` function, because if that's the case, we have a bigger problem than just a simple memory leak. I need to know how the parent/child relationship is being established here. This could become really messy, really fast. Let's see...
|
| 66/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:cx231xx_i2c_register]
Results: map[SourceCode: 510: /*
511: * cx231xx_i2c_register()
512: * register i2c bus
513: */
514: int cx231xx_i2c_register(struct cx231xx_i2c *bus)
515: {
516: struct cx231xx *dev = bus->dev;
517:
518: if (!dev->cx231xx_send_usb_command)
519: return -EINVAL;
520:
521: bus->i2c_adap = cx231xx_adap_template;
522: bus->i2c_adap.dev.parent = dev->dev;
523:
524: snprintf(bus->i2c_adap.name, sizeof(bus->i2c_adap.name), "%s-%d", bus->dev->name, bus->nr);
525:
526: bus->i2c_adap.algo_data = bus;
527: i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
528: bus->i2c_rc = i2c_add_adapter(&bus->i2c_adap);
529:
530: if (0 != bus->i2c_rc)
531: dev_warn(dev->dev,
532: "i2c bus %d register FAILED\n", bus->nr);
533:
534: return bus->i2c_rc;
535: }
SourceFile:drivers/media/usb/cx231xx/cx231xx-i2c.c]
|
| 67/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 78324
output: 27
thoughts: 43
Thoughts: Okay, here's my interpretation of that line of code, as if it were my thought process:
**Diving into the Driver Structure**
Alright, let's break this down. `bus->i2c_adap.dev.parent = dev->dev;` - This line is assigning a parent device pointer in the I2C adapter structure. The `bus` variable looks like it refers to something USB related, and the assignment looks to be establishing the parent-child relationship.
The key question is what exactly `dev->dev` is representing. It's likely a structure within `dev` that contains the actual device's information within the broader context of the USB subsystem. I need to refresh my memory on the structure here. My gut says this is some kind of core device structure.
Let's check `cx231xx_usb_probe`, that should give me a good context to what `dev` actually is. Looking at the probe routine will show me the `dev` structure is likely what is being passed in. And that the assignment sets the proper parent for the I2C adapter, which makes perfect sense for USB devices.
|
| 68/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:cx231xx_usb_probe]
Results: map[SourceCode:1685: /*
1686: * cx231xx_usb_probe()
1687: * checks for supported devices
1688: */
1689: static int cx231xx_usb_probe(struct usb_interface *interface,
1690: const struct usb_device_id *id)
1691: {
1692: struct usb_device *udev;
1693: struct device *d = &interface->dev;
1694: struct usb_interface *uif;
1695: struct cx231xx *dev = NULL;
1696: int retval = -ENODEV;
1697: int nr = 0, ifnum;
1698: int i, isoc_pipe = 0;
1699: char *speed;
1700: u8 idx;
1701: struct usb_interface_assoc_descriptor *assoc_desc;
1702:
1703: ifnum = interface->altsetting[0].desc.bInterfaceNumber;
1704:
1705: /*
1706: * Interface number 0 - IR interface (handled by mceusb driver)
1707: * Interface number 1 - AV interface (handled by this driver)
1708: */
1709: if (ifnum != 1)
1710: return -ENODEV;
1711:
1712: /* Check to see next free device and mark as used */
1713: do {
1714: nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
1715: if (nr >= CX231XX_MAXBOARDS) {
1716: /* No free device slots */
1717: dev_err(d,
1718: "Supports only %i devices.\n",
1719: CX231XX_MAXBOARDS);
1720: return -ENOMEM;
1721: }
1722: } while (test_and_set_bit(nr, &cx231xx_devused));
1723:
1724: udev = interface_to_usbdev(interface);
1725:
1726: /* allocate memory for our device state and initialize it */
1727: dev = devm_kzalloc(&interface->dev, sizeof(*dev), GFP_KERNEL);
1728: if (dev == NULL) {
1729: retval = -ENOMEM;
1730: goto err_if;
1731: }
1732:
1733: snprintf(dev->name, 29, "cx231xx #%d", nr);
1734: dev->devno = nr;
1735: dev->model = id->driver_info;
1736: dev->video_mode.alt = -1;
1737: dev->dev = d;
1738:
1739: cx231xx_set_model(dev);
1740:
1741: dev->interface_count++;
1742: /* reset gpio dir and value */
1743: dev->gpio_dir = 0;
1744: dev->gpio_val = 0;
1745: dev->xc_fw_load_done = 0;
1746: dev->has_alsa_audio = 1;
1747: dev->power_mode = -1;
1748: atomic_set(&dev->devlist_count, 0);
1749:
1750: /* 0 - vbi ; 1 -sliced cc mode */
1751: dev->vbi_or_sliced_cc_mode = 0;
1752:
1753: /* get maximum no.of IAD interfaces */
1754: dev->max_iad_interface_count = udev->config->desc.bNumInterfaces;
1755:
1756: /* init CIR module TBD */
1757:
1758: /*mode_tv: digital=1 or analog=0*/
1759: dev->mode_tv = 0;
1760:
1761: dev->USE_ISO = transfer_mode;
1762:
1763: switch (udev->speed) {
1764: case USB_SPEED_LOW:
1765: speed = "1.5";
1766: break;
1767: case USB_SPEED_UNKNOWN:
1768: case USB_SPEED_FULL:
1769: speed = "12";
1770: break;
1771: case USB_SPEED_HIGH:
1772: speed = "480";
1773: break;
1774: default:
1775: speed = "unknown";
1776: }
1777:
1778: dev_info(d,
1779: "New device %s %s @ %s Mbps (%04x:%04x) with %d interfaces\n",
1780: udev->manufacturer ? udev->manufacturer : "",
1781: udev->product ? udev->product : "",
1782: speed,
1783: le16_to_cpu(udev->descriptor.idVendor),
1784: le16_to_cpu(udev->descriptor.idProduct),
1785: dev->max_iad_interface_count);
1786:
1787: /* increment interface count */
1788: dev->interface_count++;
1789:
1790: /* get device number */
1791: nr = dev->devno;
1792:
1793: assoc_desc = udev->actconfig->intf_assoc[0];
1794: if (!assoc_desc || assoc_desc->bFirstInterface != ifnum) {
1795: dev_err(d, "Not found matching IAD interface\n");
1796: retval = -ENODEV;
1797: goto err_if;
1798: }
1799:
1800: dev_dbg(d, "registering interface %d\n", ifnum);
1801:
1802: /* save our data pointer in this interface device */
1803: usb_set_intfdata(interface, dev);
1804:
1805: /* Initialize the media controller */
1806: retval = cx231xx_media_device_init(dev, udev);
1807: if (retval) {
1808: dev_err(d, "cx231xx_media_device_init failed\n");
1809: goto err_media_init;
1810: }
1811:
1812: /* Create v4l2 device */
1813: #ifdef CONFIG_MEDIA_CONTROLLER
1814: dev->v4l2_dev.mdev = dev->media_dev;
1815: #endif
1816: retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
1817: if (retval) {
1818: dev_err(d, "v4l2_device_register failed\n");
1819: goto err_v4l2;
1820: }
1821:
1822: /* allocate device struct */
1823: retval = cx231xx_init_dev(dev, udev, nr);
1824: if (retval)
1825: goto err_init;
1826:
1827: retval = cx231xx_init_v4l2(dev, udev, interface, isoc_pipe);
1828: if (retval)
1829: goto err_init;
1830:
1831: if (dev->current_pcb_config.ts1_source != 0xff) {
1832: /* compute alternate max packet sizes for TS1 */
1833: idx = dev->current_pcb_config.hs_config_info[0].interface_info.ts1_index + 1;
1834: if (idx >= dev->max_iad_interface_count) {
1835: dev_err(d, "TS1 PCB interface #%d doesn't exist\n",
1836: idx);
1837: retval = -ENODEV;
1838: goto err_video_alt;
1839: }
1840: uif = udev->actconfig->interface[idx];
1841:
1842: if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) {
1843: retval = -ENODEV;
1844: goto err_video_alt;
1845: }
1846:
1847: dev->ts1_mode.end_point_addr =
1848: uif->altsetting[0].endpoint[isoc_pipe].
1849: desc.bEndpointAddress;
1850:
1851: dev->ts1_mode.num_alt = uif->num_altsetting;
1852: dev_info(d,
1853: "TS EndPoint Addr 0x%x, Alternate settings: %i\n",
1854: dev->ts1_mode.end_point_addr,
1855: dev->ts1_mode.num_alt);
1856:
1857: dev->ts1_mode.alt_max_pkt_size = devm_kmalloc_array(&interface->dev, 32,
1858: dev->ts1_mode.num_alt,
1859: GFP_KERNEL);
1860: if (dev->ts1_mode.alt_max_pkt_size == NULL) {
1861: retval = -ENOMEM;
1862: goto err_video_alt;
1863: }
1864:
1865: for (i = 0; i < dev->ts1_mode.num_alt; i++) {
1866: u16 tmp;
1867:
1868: if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) {
1869: retval = -ENODEV;
1870: goto err_video_alt;
1871: }
1872:
1873: tmp = le16_to_cpu(uif->altsetting[i].
1874: endpoint[isoc_pipe].desc.
1875: wMaxPacketSize);
1876: dev->ts1_mode.alt_max_pkt_size[i] =
1877: (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
1878: dev_dbg(d, "Alternate setting %i, max size= %i\n",
1879: i, dev->ts1_mode.alt_max_pkt_size[i]);
1880: }
1881: }
1882:
1883: if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
1884: cx231xx_enable_OSC(dev);
1885: cx231xx_reset_out(dev);
1886: cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3);
1887: }
1888:
1889: if (dev->model == CX231XX_BOARD_CNXT_RDE_253S)
1890: cx231xx_sleep_s5h1432(dev);
1891:
1892: /* load other modules required */
1893: request_modules(dev);
1894:
1895: #ifdef CONFIG_MEDIA_CONTROLLER
1896: /* Init entities at the Media Controller */
1897: cx231xx_v4l2_create_entities(dev);
1898:
1899: retval = v4l2_mc_create_media_graph(dev->media_dev);
1900: if (!retval)
1901: retval = media_device_register(dev->media_dev);
1902: #endif
1903: if (retval < 0)
1904: cx231xx_release_resources(dev);
1905: return retval;
1906:
1907: err_video_alt:
1908: /* cx231xx_uninit_dev: */
1909: cx231xx_close_extension(dev);
1910: cx231xx_ir_exit(dev);
1911: cx231xx_release_analog_resources(dev);
1912: cx231xx_417_unregister(dev);
1913: cx231xx_remove_from_devlist(dev);
1914: cx231xx_dev_uninit(dev);
1915: err_init:
1916: v4l2_device_unregister(&dev->v4l2_dev);
1917: err_v4l2:
1918: cx231xx_unregister_media_device(dev);
1919: err_media_init:
1920: usb_set_intfdata(interface, NULL);
1921: err_if:
1922: clear_bit(nr, &cx231xx_devused);
1923: return retval;
1924: }
SourceFile:drivers/media/usb/cx231xx/cx231xx-cards.c]
|
| 69/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 82451
output: 23
thoughts: 446
Thoughts: **Analyzing a Kernel Use-After-Free Vulnerability**
Okay, let's break this down. We have a Use-After-Free (UAF) report and I need to figure out what's going on. The initial thought process began with `dev->dev = d;` where `d = &interface->dev;`. So, `cx231xx` sets `bus->i2c_adap.dev.parent = &interface->dev;`. I immediately realized that `interface->dev` is a `usb_interface`. But, the KASAN report is screaming about the UAF occurring on a `usb_device`, not the interface! That's a huge discrepancy. If the parent were a `usb_interface`, the allocation size for the parent should be `kmalloc-2k`, not the `kmalloc-4k` size associated with a `usb_device`. This means `cx231xx` *isn't* the culprit here.
Alright, let's pivot and examine `dvb_usb_device` closely. Examining the code, I see that `d->i2c_adap.dev.parent = &d->udev->dev;` - and `d->udev` *is* the `usb_device`. Perfect, this matches the reported UAF location. Furthermore, `dvb_usb_device` is freed in `dvb_usbv2_disconnect` with `kfree(d)`. But, hold on... if `d` is freed, then `d->i2c_adap` *should* be freed as well! Which means KASAN should have reported a UAF on `d` itself, which is `kmalloc-16k`. However, the report shows the UAF on `usb_device` (specifically `kmalloc-4k`) meaning that `d->i2c_adap` isn't freed! That is the core of the problem - why is `d->i2c_adap` not being freed? How is this even possible?
Maybe `d` *isn't* freed. I should reread `dvb_usbv2_disconnect`'s code again. I see it now:
```c
if (d->props->disconnect)
d->props->disconnect(d);
kfree(d->priv);
kfree(d);
```
Nope, `kfree(d)` *is* called. So, the `dvb_usb_device` itself *is* freed, which still doesn't explain how the adapter is left dangling, causing the UAF on the `usb_device`.
Alright, I'm at the point where I have to think more broadly. Is there another driver that dynamically allocates an `i2c_adapter` and sets its `parent` to the `usb_device`? Time to investigate and see if the `hdpvr` driver does something like this.
|
| 70/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 264: static int hdpvr_probe(struct usb_interface *interface,
265: const struct usb_device_id *id)
266: {
267: struct hdpvr_device *dev;
268: struct usb_endpoint_descriptor *endpoint;
269: #if IS_ENABLED(CONFIG_I2C)
270: struct i2c_client *client;
271: #endif
272: int dev_num;
273: int retval = -ENOMEM;
274:
275: /* allocate memory for our device state and initialize it */
276: dev = kzalloc_obj(*dev);
277: if (!dev) {
278: dev_err(&interface->dev, "Out of memory\n");
279: goto error;
280: }
281:
282: /* init video transfer queues first of all */
283: /* to prevent oops in hdpvr_delete() on error paths */
284: INIT_LIST_HEAD(&dev->free_buff_list);
285: INIT_LIST_HEAD(&dev->rec_buff_list);
286:
287: /* register v4l2_device early so it can be used for printks */
288: if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
289: dev_err(&interface->dev, "v4l2_device_register failed\n");
290: goto error_free_dev;
291: }
292:
293: mutex_init(&dev->io_mutex);
294: mutex_init(&dev->i2c_mutex);
295: mutex_init(&dev->usbc_mutex);
296: dev->usbc_buf = kmalloc(64, GFP_KERNEL);
297: if (!dev->usbc_buf) {
298: v4l2_err(&dev->v4l2_dev, "Out of memory\n");
299: goto error_v4l2_unregister;
300: }
301:
302: init_waitqueue_head(&dev->wait_buffer);
303: init_waitqueue_head(&dev->wait_data);
304:
305: dev->options = hdpvr_default_options;
306:
307: if (default_video_input < HDPVR_VIDEO_INPUTS)
308: dev->options.video_input = default_video_input;
309:
310: if (default_audio_input < HDPVR_AUDIO_INPUTS) {
311: dev->options.audio_input = default_audio_input;
312: if (default_audio_input == HDPVR_SPDIF)
313: dev->options.audio_codec =
314: V4L2_MPEG_AUDIO_ENCODING_AC3;
315: }
316:
317: dev->udev = usb_get_dev(interface_to_usbdev(interface));
318:
319: /* set up the endpoint information */
320: /* use only the first bulk-in and bulk-out endpoints */
321: if (usb_find_bulk_in_endpoint(interface->cur_altsetting, &endpoint)) {
322: v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n");
323: goto error_put_usb;
324: }
325:
326: /*
327: * USB interface description is buggy, reported max packet size is 512
328: * bytes, windows driver uses 8192
329: */
330: dev->bulk_in_size = 8192;
331: dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
332:
333: /* init the device */
334: if (hdpvr_device_init(dev)) {
335: v4l2_err(&dev->v4l2_dev, "device init failed\n");
336: goto error_put_usb;
337: }
338:
339: mutex_lock(&dev->io_mutex);
340: if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) {
341: mutex_unlock(&dev->io_mutex);
342: v4l2_err(&dev->v4l2_dev,
343: "allocating transfer buffers failed\n");
344: goto error_put_usb;
345: }
346: mutex_unlock(&dev->io_mutex);
347:
348: #if IS_ENABLED(CONFIG_I2C)
349: retval = hdpvr_register_i2c_adapter(dev);
350: if (retval < 0) {
351: v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n");
352: goto error_free_buffers;
353: }
354:
355: client = hdpvr_register_ir_i2c(dev);
356: if (IS_ERR(client)) {
357: v4l2_err(&dev->v4l2_dev, "i2c IR device register failed\n");
358: retval = PTR_ERR(client);
359: goto reg_fail;
360: }
361: #endif
362:
363: dev_num = atomic_inc_return(&dev_nr);
364: if (dev_num >= HDPVR_MAX) {
365: v4l2_err(&dev->v4l2_dev,
366: "max device number reached, device register failed\n");
367: atomic_dec(&dev_nr);
368: retval = -ENODEV;
369: goto reg_fail;
370: }
371:
372: retval = hdpvr_register_videodev(dev, &interface->dev,
373: video_nr[dev_num]);
374: if (retval < 0) {
375: v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
376: goto reg_fail;
377: }
378:
379: /* let the user know what node this device is now attached to */
380: v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
381: video_device_node_name(&dev->video_dev));
382: return 0;
383:
384: reg_fail:
385: #if IS_ENABLED(CONFIG_I2C)
386: i2c_del_adapter(&dev->i2c_adapter);
387: error_free_buffers:
388: #endif
389: hdpvr_free_buffers(dev);
390: error_put_usb:
391: usb_put_dev(dev->udev);
392: kfree(dev->usbc_buf);
393: error_v4l2_unregister:
394: v4l2_device_unregister(&dev->v4l2_dev);
395: error_free_dev:
396: kfree(dev);
397: error:
398: return retval;
399: }
SourceFile:drivers/media/usb/hdpvr/hdpvr-core.c]
|
| 71/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 85779
output: 23
thoughts: 33
Thoughts: Here's a breakdown of my thought process:
**Diving into hdpvr_disconnect**
Okay, so I'm looking at the `hdpvr_probe` function. The first thing that jumps out is the allocation of `dev` using `kzalloc_obj(*dev)`. I need to remember that. It's allocated there via `kzalloc_obj`, which is important for understanding the lifecycle of this structure. Now, I want to see how that `dev` is handled on the disconnect path. I'm going to shift my focus to `hdpvr_disconnect` to understand how the driver cleans up after itself and, specifically, if the memory allocated for `dev` is properly freed. Understanding the pair of probe and disconnect gives a full picture of the driver's memory management.
|
| 72/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:hdpvr_disconnect]
Results: map[SourceCode: 401: static void hdpvr_disconnect(struct usb_interface *interface)
402: {
403: struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface));
404:
405: v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
406: video_device_node_name(&dev->video_dev));
407: /* prevent more I/O from starting and stop any ongoing */
408: mutex_lock(&dev->io_mutex);
409: dev->status = STATUS_DISCONNECTED;
410: wake_up_interruptible(&dev->wait_data);
411: wake_up_interruptible(&dev->wait_buffer);
412: mutex_unlock(&dev->io_mutex);
413: v4l2_device_disconnect(&dev->v4l2_dev);
414: msleep(100);
415: flush_work(&dev->worker);
416: mutex_lock(&dev->io_mutex);
417: hdpvr_cancel_queue(dev);
418: mutex_unlock(&dev->io_mutex);
419: #if IS_ENABLED(CONFIG_I2C)
420: i2c_del_adapter(&dev->i2c_adapter);
421: #endif
422: video_unregister_device(&dev->video_dev);
423: atomic_dec(&dev_nr);
424: }
SourceFile:drivers/media/usb/hdpvr/hdpvr-core.c]
|
| 73/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 86477
output: 23
thoughts: 52
Thoughts: **My Concerns Regarding Device Deallocation in the HDPVR Driver**
Okay, so I'm digging into this `hdpvr_disconnect` function and something's immediately jumping out at me. I see that `hdpvr_disconnect` is responsible for unregistering the video device using `video_unregister_device(&dev->video_dev)`. However, it *doesn't* appear to free the `dev` pointer itself. That's a potential memory leak if we're not careful. This warrants further investigation, as a resource should always be deallocated after being unregistered.
The question then becomes: where *is* `dev` getting freed? I need to trace the lifecycle of this `dev` structure to ensure there's a corresponding `kfree` somewhere. My next step is to examine the `hdpvr_release` function. That seems like the most likely place where this crucial deallocation would occur. I need to understand the logic in `hdpvr_release` to confirm or refute my suspicion and confirm there are no memory management problems in the driver.
|
| 74/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 392: static int hdpvr_release(struct file *file)
393: {
394: struct hdpvr_device *dev = video_drvdata(file);
395:
396: mutex_lock(&dev->io_mutex);
397: if (file_to_v4l2_fh(file) == dev->owner) {
398: hdpvr_stop_streaming(dev);
399: dev->owner = NULL;
400: }
401: mutex_unlock(&dev->io_mutex);
402:
403: return v4l2_fh_release(file);
404: }
SourceFile:drivers/media/usb/hdpvr/hdpvr-video.c]
|
| 75/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 87014
output: 25
thoughts: 40
Thoughts: **Debugging Memory Management in `hdpvr`**
Okay, so I'm digging into this `hdpvr` code again. I was just reviewing the `hdpvr_release` function, and it suddenly hit me: wait a minute, this function *isn't* freeing the `dev` structure! I'm pretty sure I thought it did. Where *is* the memory allocated to `dev` being released? This is a critical point; a memory leak here would be pretty nasty. Alright, time to trace this down. Let's shift our focus to `hdpvr_device_release`, that seems like the next logical place to start looking. I'm hoping I'll find the answer in there.
|
| 76/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:hdpvr_device_release]
Results: map[SourceCode:1130: static void hdpvr_device_release(struct video_device *vdev)
1131: {
1132: struct hdpvr_device *dev = video_get_drvdata(vdev);
1133:
1134: hdpvr_delete(dev);
1135: flush_work(&dev->worker);
1136:
1137: v4l2_device_unregister(&dev->v4l2_dev);
1138: v4l2_ctrl_handler_free(&dev->hdl);
1139:
1140: /* deregister I2C adapter */
1141: #if IS_ENABLED(CONFIG_I2C)
1142: mutex_lock(&dev->i2c_mutex);
1143: i2c_del_adapter(&dev->i2c_adapter);
1144: mutex_unlock(&dev->i2c_mutex);
1145: #endif /* CONFIG_I2C */
1146:
1147: kfree(dev->usbc_buf);
1148: kfree(dev);
1149: }
SourceFile:drivers/media/usb/hdpvr/hdpvr-video.c]
|
| 77/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 87587
output: 29
thoughts: 287
Thoughts: **UAF Investigation - HDPVR Driver**
Okay, so I'm looking at this `hdpvr` driver code. Specifically, the cleanup process β I see that `hdpvr_device_release` calls `kfree(dev)`. That makes sense; it's the standard way to deallocate memory. And it's triggered when the `video_device` refcount hits zero.
But then I see something that makes me pause: `hdpvr_disconnect` also calls `i2c_del_adapter(&dev->i2c_adapter)`. And `hdpvr_device_release` *also* calls it! Now, that double call to `i2c_del_adapter` raises a red flag immediately. A double free situation is a classic bug. I wonder, is this somehow protected? We need to investigate.
The good news is that if `/dev/videoX` is kept open, `hdpvr_device_release` isn't called. Which means `dev` *isn't* freed. And that also means `dev->i2c_adapter` isn't freed either! But the `usb_device` *is* freed! Hmm, this is getting interesting.
Here's the idea: If we open `/dev/videoX`, disconnect the USB device, and *then* try to do an `I2C_SMBUS` ioctl on `/dev/i2c-X`, we could trigger a Use-After-Free (UAF) condition! That `i2c_adapter` struct is pointing to memory that's been freed. Let's see if we can trigger this UAF!
Hold on, I think I've got it. I recall that `hdpvr` sets `dev->i2c_adapter.dev.parent = &dev->udev->dev;` And `dev->udev` is the `usb_device`. So that perfectly matches the scenario: the I2C adapter's parent is the USB device.
Okay, let's take a look at the `pvrusb2` code too, just to be sure. I want to see if this pattern is re-used or a pattern of code reuse.
|
| 78/2 |
2026/07/30 12:21 |
tool |
codesearch-definition-source |
0m
Args: map[Name:pvr2_i2c_core_init]
Results: map[SourceCode: 591: void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
592: {
593: unsigned int idx;
594:
595: /* The default action for all possible I2C addresses is just to do
596: the transfer normally. */
597: for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
598: hdw->i2c_func[idx] = pvr2_i2c_basic_op;
599: }
600:
601: /* However, deal with various special cases for 24xxx hardware. */
602: if (ir_mode[hdw->unit_number] == 0) {
603: pr_info("%s: IR disabled\n", hdw->name);
604: hdw->i2c_func[0x18] = i2c_black_hole;
605: } else if (ir_mode[hdw->unit_number] == 1) {
606: if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) {
607: /* Set up translation so that our IR looks like a
608: 29xxx device */
609: hdw->i2c_func[0x18] = i2c_24xxx_ir;
610: }
611: }
612: if (hdw->hdw_desc->flag_has_cx25840) {
613: hdw->i2c_func[0x44] = i2c_hack_cx25840;
614: }
615: if (hdw->hdw_desc->flag_has_wm8775) {
616: hdw->i2c_func[0x1b] = i2c_hack_wm8775;
617: }
618:
619: // Configure the adapter and set up everything else related to it.
620: hdw->i2c_adap = pvr2_i2c_adap_template;
621: hdw->i2c_algo = pvr2_i2c_algo_template;
622: strscpy(hdw->i2c_adap.name, hdw->name, sizeof(hdw->i2c_adap.name));
623: hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
624: hdw->i2c_adap.algo = &hdw->i2c_algo;
625: hdw->i2c_adap.algo_data = hdw;
626: hdw->i2c_linked = !0;
627: i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
628: i2c_add_adapter(&hdw->i2c_adap);
629: if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
630: /* Probe for a different type of IR receiver on this
631: device. This is really the only way to differentiate
632: older 24xxx devices from 24xxx variants that include an
633: IR blaster. If the IR blaster is present, the IR
634: receiver is part of that chip and thus we must disable
635: the emulated IR receiver. */
636: if (do_i2c_probe(hdw, 0x71)) {
637: pvr2_trace(PVR2_TRACE_INFO,
638: "Device has newer IR hardware; disabling unneeded virtual IR device");
639: hdw->i2c_func[0x18] = NULL;
640: /* Remember that this is a different device... */
641: hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE;
642: }
643: }
644: if (i2c_scan) do_i2c_scan(hdw);
645:
646: pvr2_i2c_register_ir(hdw);
647: }
SourceFile:drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c]
|
| 79/2 |
2026/07/30 12:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 89632
output: 27
thoughts: 1882
Thoughts: **Unraveling the I2C Adapter UAF Bug**
Okay, let's break this down. The fuzzer triggered a Use-After-Free (UAF) on a `usb_device`, and it looks like the culprit is in how I2C adapters are handled in relation to USB device lifecycles.
My initial thought is that `pvrusb2` sets `hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;`, and `hdw` (likely the structure containing the I2C adapter) is freed when its reference count hits zero. If a `/dev/videoX` is open, `hdw` isn't freed. But that isn't the whole story.
The KASAN report indicates the `usb_device` itself is getting allocated, freed, and then resurrected as `skb->head` due to some side effect of the fuzzer. The critical flaw is in how an `i2c_adapter`'s `dev.parent` is linked to a `usb_device` which can be freed while the adapter is still alive. This means any driver that does this, and doesn't explicitly free the adapter when disconnecting, is vulnerable.
Let's check drivers like `au0828`, `hdpvr`, `pvrusb2`, `cx231xx`, `dvb_usb_v2`, and `dvb_usb`. `dvb_usb_v2` and `dvb_usb` free `d` which houses their I2C adapter in their `disconnect` function. But if `d` is freed while the adapter's still in use, KASAN should report UAF on `d`, which is the `kmalloc-16k` memory block. But the report says UAF on `usb_device`, which is the `kmalloc-4k` memory block. That means we should look at drivers which do *not* free the adapter in disconnect. `au0828`, `hdpvr`, and `pvrusb2` are the leading candidates.
`hdpvr` calls `i2c_del_adapter` during disconnect. Does `i2c_del_adapter` free the `i2c_adapter`? No, `i2c_del_adapter` unregisters the device, but the memory is freed with the containing struct. However, if the `/dev/i2c-X` device has been opened before the disconnect, `i2c_get_adapter` will have incremented the `adapter->dev`'s reference count. Then, during disconnect, `i2c_del_adapter` unregisters the device. `device_unregister` drops the parent's refcount (`usb_device`). If this was the last reference to `usb_device`, it is freed. But the adapter's refcount is still > 0, so the adapter itself is NOT freed. Then the `I2C_SMBUS` ioctl gets called on `/dev/i2c-X`, which calls through to `i2c_adapter_depth`, which accesses `adapter->dev.parent->type`. But `adapter->dev.parent` is now pointing to a freed `usb_device`! This perfectly explains the KASAN UAF on `usb_device`!
This means any driver with that pattern is at risk! Now, let's explore the `dvb_usb_device` case. If `/dev/i2c-X` is open, `i2c_get_adapter` holds a reference to the adapter. However, the disconnect function frees `dvb_usb_device` and therefore also the adapter! This would be a UAF on `dvb_usb_device`, not the `usb_device`. Since the KASAN report is on `usb_device`, the driver must *not* be freeing the `i2c_adapter` on disconnect. This points back to `au0828`, `hdpvr`, and `pvrusb2`, as they do NOT free the struct on disconnect if `/dev/videoX` is open.
What if `/dev/videoX` is not open? Does `i2c_get_adapter` prevent the struct from being freed? It calls `try_module_get` and `get_device`. This does not increment the refcount of the structure. So if `/dev/videoX` is *not* open, the driver's disconnect function *might* free the struct. However, if the driver *does* free the struct in `disconnect`, it's still a bug because the adapter is still referenced. For example, `au0828` calls `au0
|
| 80/2 |
2026/07/30 12:22 |
tool |
codesearch-definition-source |
0m
Args: map[Name:i2c_adapter_dev_release]
Results: map[SourceCode:1231: static void i2c_adapter_dev_release(struct device *dev)
1232: {
1233: struct i2c_adapter *adap = to_i2c_adapter(dev);
1234: complete(&adap->dev_released);
1235: }
SourceFile:drivers/i2c/i2c-core-base.c]
|
| 81/2 |
2026/07/30 12:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 92685
output: 25
thoughts: 16
Thoughts: Okay, here's the summarized thought process, as if it were my own, assuming the role of an expert:
**Concerning I2C Adapter Deletion and Completion**
Right, so `i2c_del_adapter` is the crucial function here. And the key thing to lock in is that, yes, it *does* wait for the completion of the operations it initiates. This isn't always obvious in all asynchronous contexts, so confirming this is essential for understanding the overall data flow and synchronization. I need to keep this in mind as I analyse the surrounding code; understanding if there are any race conditions here, and ensuring this synchronization is being handled correctly. This waiting behaviour is likely fundamental to maintaining data integrity and preventing resource corruption. So I'm glad this detail is clear in my mind.
|
| 82/2 |
2026/07/30 12:22 |
tool |
codesearch-definition-source |
0m
Args: map[Name:i2c_del_adapter]
Results: map[SourceCode:1795: /**
1796: * i2c_del_adapter - unregister I2C adapter
1797: * @adap: the adapter being unregistered
1798: * Context: can sleep
1799: *
1800: * This unregisters an I2C adapter which was previously registered
1801: * by @i2c_add_adapter or @i2c_add_numbered_adapter.
1802: */
1803: void i2c_del_adapter(struct i2c_adapter *adap)
1804: {
1805: struct i2c_adapter *found;
1806:
1807: /* First make sure that this adapter was ever added */
1808: mutex_lock(&core_lock);
1809: found = idr_find(&i2c_adapter_idr, adap->nr);
1810: if (found == adap)
1811: idr_replace(&i2c_adapter_idr, NULL, adap->nr);
1812: mutex_unlock(&core_lock);
1813: if (found != adap) {
1814: pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
1815: return;
1816: }
1817:
1818: i2c_acpi_remove_space_handler(adap);
1819:
1820: i2c_deregister_clients(adap);
1821:
1822: /* device name is gone after device_unregister */
1823: dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
1824:
1825: pm_runtime_disable(&adap->dev);
1826:
1827: i2c_host_notify_irq_teardown(adap);
1828:
1829: debugfs_remove_recursive(adap->debugfs);
1830:
1831: /* wait until all references to the device are gone
1832: *
1833: * FIXME: This is old code and should ideally be replaced by an
1834: * alternative which results in decoupling the lifetime of the struct
1835: * device from the i2c_adapter, like spi or netdev do. Any solution
1836: * should be thoroughly tested with DEBUG_KOBJECT_RELEASE enabled!
1837: */
1838: init_completion(&adap->dev_released);
1839: device_unregister(&adap->dev);
1840: wait_for_completion(&adap->dev_released);
1841:
1842: /* free bus id */
1843: mutex_lock(&core_lock);
1844: idr_remove(&i2c_adapter_idr, adap->nr);
1845: mutex_unlock(&core_lock);
1846:
1847: /* Clear the device structure in case this adapter is ever going to be
1848: added again */
1849: memset(&adap->dev, 0, sizeof(adap->dev));
1850: }
SourceFile:drivers/i2c/i2c-core-base.c]
|
| 83/2 |
2026/07/30 12:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 93788
output: 29
thoughts: 2645
Thoughts: **The I2C Adapter UAF Saga**
Okay, so here's the breakdown of this frustrating I2C adapter Use-After-Free (UAF) situation. It all revolves around how the `i2c_del_adapter` function interacts with the USB device removal process. My initial thought process was:
1. `i2c_del_adapter` blocks until all references to the I2C adapter's device are gone. Makes sense.
2. If `/dev/i2c-X` (the character device) is open, the reference count for the adapter increases with `i2c_get_adapter`. Then `i2c_del_adapter` blocks. That's a problem in the `disconnect` callback if it has to block.
3. That block causes the entire USB device disconnect to block in the `disconnect` function. That cannot be right. The USB device is not freed if disconnect blocks! But the KASAN report indicates it IS freed. That's a contradiction.
4. Then I started tracing the refcounts of the `usb_device`, specifically considering `usb_disconnect` and how the device is un-registered.
5. I had to think about how parents are handled: `device_unregister` calls `device_del` which calls `put_device(parent)`. If the "parent" of the I2C adapter is the `usb_device`, then the refcount of `usb_device` drops. But when?
6. The `usb_device` is referenced by the USB core. So, even if the parent reference drops, it is still being referenced.
7. `usb_disconnect` calls `device_del(&udev->dev)`, which drops the reference to the parent. That is the USB driver's device structure.
8. I asked myself, when does the `udev` refcount drop to 0? That happens in `usb_release_dev`.
9. If `i2c_del_adapter` is called *during* `usb_disconnect`, it has to be called inside `disconnect` so how can it work?
10. So I went back and went through the logic. I realized `i2c_del_adapter` does **not** call `put_device(udev)` **directly**. I traced the `put_device` function from both `usb_disconnect` and `device_unregister`.
11. Here's the key: What if the driver doesn't call `i2c_del_adapter` directly from the `disconnect` callback, but instead calls it from a *different* callback, like a release callback?
12. Aha! If the driver calls `i2c_del_adapter` later, the USB device's resources might be freed *before* the I2C adapter is unregistered. The driver in this case will be at fault.
13. If `/dev/videoX` is open, the driver's `disconnect` returns without calling `i2c_del_adapter`.
14. `usb_disconnect` continues!
15. `usb_disconnect` calls `device_del(&intf->dev)`, which drops the `udev` refcount and then finishes and calls `put_device(&udev->dev)`. The `udev` is freed. BUT the I2C adapter is STILL registered.
16. This is where the UAF happens: We try to use `/dev/i2c-X`, and it accesses `adapter->dev.parent->type` which is accessing the freed `udev` memory. BINGO!
**Identifying the Culprit**
So, the key is finding a driver that:
* Defers `i2c_del_adapter` to a release callback, usually if there are open users.
* Does *not* call `i2c_del_adapter` directly in `disconnect` if users are present.
`au0828` does exactly that. It calls `au0828_usb_release` from `au0828_usb_v4l2_release`, which is called when the `v4l2_device` refcount drops. If V4L2 is enabled, the adapter is never un-registered in disconnect.
**Verification and Reproducibility**
I verified that `au0828` indeed defers the unregistration.
`pvrusb2` is complex.
`hdpvr` does not appear to be the same, because it calls `i2c_del_adapter` directly from `disconnect`.
The best candidate for a reproducer is `au082
|
| 84/2 |
2026/07/30 12:22 |
tool |
codesearch-definition-source |
0m
Args: map[Name:au0828_usb_id_table]
Results: map[SourceCode: 351: /* table of devices that work with this driver */
352: struct usb_device_id au0828_usb_id_table[] = {
353: { USB_DEVICE(0x2040, 0x7200),
354: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
355: { USB_DEVICE(0x2040, 0x7240),
356: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
357: { USB_DEVICE(0x0fe9, 0xd620),
358: .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
359: { USB_DEVICE(0x2040, 0x7210),
360: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
361: { USB_DEVICE(0x2040, 0x7217),
362: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
363: { USB_DEVICE(0x2040, 0x721b),
364: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
365: { USB_DEVICE(0x2040, 0x721e),
366: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
367: { USB_DEVICE(0x2040, 0x721f),
368: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
369: { USB_DEVICE(0x2040, 0x7280),
370: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
371: { USB_DEVICE(0x0fd9, 0x0008),
372: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
373: { USB_DEVICE(0x2040, 0x7201),
374: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
375: { USB_DEVICE(0x2040, 0x7211),
376: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
377: { USB_DEVICE(0x2040, 0x7281),
378: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
379: { USB_DEVICE(0x05e1, 0x0480),
380: .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
381: { USB_DEVICE(0x2040, 0x8200),
382: .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
383: { USB_DEVICE(0x2040, 0x7260),
384: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
385: { USB_DEVICE(0x2040, 0x7213),
386: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
387: { USB_DEVICE(0x2040, 0x7270),
388: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
389: { USB_DEVICE(0x2040, 0x72b0),
390: .driver_info = AU0828_BOARD_HAUPPAUGE_IMPACTVCBE },
391: { USB_DEVICE(0x2040, 0x72a0),
392: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR1265 },
393: { },
394: };
SourceFile:drivers/media/usb/au0828/au0828-cards.c]
|
| 85/2 |
2026/07/30 12:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 98784
output: 19
thoughts: 154
Thoughts: **Reproducer Design for USB and I2C Interaction**
Okay, so I'm thinking, let's start with those addresses: `0x2040, 0x7200`. Now, how do I actually build this syzkaller reproducer? Right, the USB device. I can use `syz_usb_connect` to attach the device. Then, I need to open the relevant device file β something like `/dev/video0`, or whatever gets created. After that, disconnect it with `syz_usb_disconnect`. Next, I'll need to open something like `/dev/i2c-0`, the I2C interface. Finally, I'll use `ioctl(fd, I2C_SMBUS, ...)` for the I2C transaction.
Hmm, a quick check. Ah yes, `syz_usb_connect` and `syz_usb_disconnect` are pseudo-syscalls. Fine, I'll just double-check the syntax of `syz_usb_connect` to make sure I get that right.
|
| 86/2 |
2026/07/30 12:23 |
tool |
read-description |
0m
Args:
Results: map[Output:# Copyright 2019 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
include <linux/types.h>
include <linux/byteorder/generic.h>
include <uapi/linux/usb/ch9.h>
include <uapi/linux/usb/ch11.h>
include <uapi/linux/usb/midi.h>
include <uapi/linux/usb/audio.h>
include <linux/usb/audio-v2.h>
include <linux/usb/audio-v3.h>
include <uapi/linux/hid.h>
include <linux/hid.h>
include <uapi/linux/usb/cdc.h>
include <uapi/linux/if_ether.h>
include <linux/interrupt.h>
include <linux/usb/cdc_ncm.h>
include <drivers/net/usb/asix.h>
# This is a special fd for USB fuzzing and should only be used with syz_usb_* pseudo-syscalls.
# We don't inherit it from the fd resource, to discourage syzkaller calling raw ioctls on it.
resource fd_usb[int32]: -1
# These are generic pseudo-syscalls for emulating arbitrary USB devices.
# They are mostly targeted to cover the enumeration process.
syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io(fd fd_usb, descs ptr[in, vusb_descriptors], resps ptr[in, vusb_responses]) (timeout[300], remote_cover)
syz_usb_ep_write(fd fd_usb, ep int8, len len[data], data ptr[in, array[int8, 0:256]]) (timeout[300], remote_cover)
syz_usb_ep_read(fd fd_usb, ep int8, len len[data], data buffer[out]) (timeout[300], remote_cover)
syz_usb_disconnect(fd fd_usb) (timeout[300], remote_cover)
usb_device_speed = USB_SPEED_UNKNOWN, USB_SPEED_LOW, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_WIRELESS, USB_SPEED_SUPER, USB_SPEED_SUPER_PLUS
# TODO: consider patching idVendor and idProduct for all class specific descriptions in Go code to cover more drivers.
# TODO: custom syz_usb_ep_write() descriptions for all class specific descriptions.
# TODO: consider adding custom vusb_connect_descriptors definitions to all class specific descriptions.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
type usb_device_descriptor_verbose_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] {
bLength const[USB_DT_DEVICE_SIZE, int8]
bDescriptorType const[USB_DT_DEVICE, int8]
bcdUSB USB
bDeviceClass const[CLASS, int8]
bDeviceSubClass const[SUBCLASS, int8]
bDeviceProtocol const[PROTOCOL, int8]
bMaxPacketSize0 PACKET
idVendor const[VENDOR, int16]
idProduct const[PRODUCT, int16]
bcdDevice const[DEVICE, int16]
iManufacturer const[1, int8]
iProduct const[2, int8]
iSerialNumber const[3, int8]
bNumConfigurations len[configs, int8]
configs CFS
} [packed]
type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[flags[usb_versions, int16], CLASS, SUBCLASS, PROTOCOL, flags[usb_device_max_packet_sizes, int8], VENDOR, PRODUCT, DEVICE, CFS]
type usb_device_descriptor_fixed_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[const[USB, int16], CLASS, SUBCLASS, PROTOCOL, const[PACKET, int8], VENDOR, PRODUCT, DEVICE, CFS]
usb_versions = 0x110, 0x200, 0x201, 0x250, 0x300, 0x310
# https://elixir.bootlin.com/linux/v5.1.7/source/drivers/usb/core/hub.c#L4661
usb_device_max_packet_sizes = 8, 16, 32, 64, 255
type usb_config_descriptor_verbose_t[NUM, IFSNUM, ICONFIG, ATTRS, POWER, EXTRA, IFS] {
bLength const[USB_DT_CONFIG_SIZE, int8]
bDescriptorType const[USB_DT_CONFIG, int8]
wTotalLength len[parent, int16]
bNumInterfaces IFSNUM
bConfigurationValue NUM
iConfiguration ICONFIG
bmAttributes ATTRS
bMaxPower POWER
extra EXTRA
interfaces IFS
} [packed]
type usb_config_descriptor_t[NUM, IFSNUM, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, void, IFS]
type usb_config_descriptor_ifaces_array_t[NUM, IFS] usb_config_descriptor_t[NUM, len[interfaces, int8], IFS]
type usb_config_descriptor_fixed_t[NUM, IFSNUM, ATTRS, POWER, IFS] usb_config_descriptor_verbose_t[const[NUM, int8], const[IFSNUM, int8], const[0, int8], const[ATTRS, int8], const[POWER, int8], void, IFS]
type usb_config_descriptor_extra_t[NUM, IFSNUM, EXTRA, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, EXTRA, IFS]
type usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, IIF, EXTRA, EPS] {
bLength const[USB_DT_INTERFACE_SIZE, int8]
bDescriptorType const[USB_DT_INTERFACE, int8]
bInterfaceNumber IFNUM
bAlternateSetting ALTNUM
bNumEndpoints EPSNUM
bInterfaceClass CLASS
bInterfaceSubClass SUBCLASS
bInterfaceProtocol PROTOCOL
iInterface IIF
extra EXTRA
endpoints EPS
} [packed]
type usb_interface_descriptor_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, int8, EXTRA, EPS]
type usb_interface_descriptor_eps_array_t[IFNUM, ALTNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_t[IFNUM, ALTNUM, len[endpoints, int8], CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS]
type usb_interface_descriptor_fixed_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[const[IFNUM, int8], const[ALTNUM, int8], const[EPSNUM, int8], const[CLASS, int8], const[SUBCLASS, int8], const[PROTOCOL, int8], const[0, int8], EXTRA, EPS]
# TODO: non-audio endpoints have USB_DT_ENDPOINT_SIZE.
type usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, PACKET, INTERVAL, REFRESH, SYNCH, EXTRA] {
bLength const[USB_DT_ENDPOINT_AUDIO_SIZE, int8]
bDescriptorType const[USB_DT_ENDPOINT, int8]
bEndpointAddress ADDR
bmAttributes ATTRS
wMaxPacketSize PACKET
bInterval INTERVAL
bRefresh REFRESH
bSynchAddress SYNCH
extra EXTRA
} [packed]
type usb_endpoint_descriptor_t[ADDR, ATTRS, EXTRA] usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, EXTRA]
type usb_endpoint_descriptor_fixed_t[ADDR, ATTRS, PACKET, INTERVAL, EXTRA] usb_endpoint_descriptor_verbose_t[const[ADDR, int8], const[ATTRS, int8], const[PACKET, int16], const[INTERVAL, int8], const[0, int8], const[0, int8], EXTRA]
# TODO: dummy driver has complex requirements for packet sizes, account for those:
# https://elixir.bootlin.com/linux/v5.3.6/source/drivers/usb/gadget/udc/dummy_hcd.c#L497
usb_endpoint_max_packet_sizes = 8, 16, 32, 64, 512, 1023, 1024
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Generic USB device, configuration, interface and endpoint descriptors.
# We only support one configuration per device.
# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct
# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]]
} [packed]
usb_config_descriptor {
inner usb_config_descriptor_ifaces_array_t[int8, array[usb_interface_descriptor, 1:4]]
} [packed]
usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY
# bInterfaceNumber, bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol
# are patched by Go code, see sys/linux/init_vusb.go.
usb_interface_descriptor {
inner usb_interface_descriptor_eps_array_t[int8, int8, const[0, int8], const[0, int8], const[0, int8], array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
} [packed]
usb_endpoint_descriptor {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], array[usb_endpoint_extra_descriptor, 0:2]]
} [packed]
usb_endpoint_addresses = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, USB_DIR_OUT, USB_DIR_IN
usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK
vusb_connect_descriptors {
qual_len len[qual, int32]
qual ptr[in, usb_qualifier_descriptor]
bos_len len[bos, int32]
bos ptr[in, usb_bos_descriptor]
strs_len len[strs, int32]
strs array[vusb_connect_string_descriptor]
} [packed]
vusb_connect_string_descriptor {
len len[str, int32]
str ptr[in, usb_string_descriptor]
} [packed]
vusb_descriptors {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]]
hub_hs ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_HUB, usb_hub_descriptor_hs]]
hub_ss ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_SS_HUB, usb_hub_descriptor_ss]]
} [packed]
vusb_descriptor_generic {
req_type flags[usb_request_types, int8]
desc_type flags[usb_descriptor_types, int8]
len bytesize[data, int32]
data usb_generic_descriptor
} [packed]
usb_request_types = USB_TYPE_STANDARD, USB_TYPE_CLASS, USB_TYPE_VENDOR
type vusb_descriptor_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# TODO: consider doing lookups based on USB_RECIP values.
vusb_responses {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
get_interface ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
get_configuration ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
# TODO: move these into custom descriptions for hub class when they are added.
hub_USB_REQ_GET_STATUS_hub ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_hub_status]]
hub_USB_REQ_GET_STATUS_port ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_port_status]]
# TODO: move these into custom descriptions for asix driver when they are added.
asix_AX_CMD_READ_MII_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MII_REG, int16]]
asix_AX_CMD_STATMNGSTS_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_STATMNGSTS_REG, int8]]
asix_AX_CMD_READ_EEPROM ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_EEPROM, array[int8, 2]]]
asix_AX_CMD_READ_RX_CTL ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_RX_CTL, int16]]
asix_AX_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_NODE_ID, mac_addr]]
asix_AX88172_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX88172_CMD_READ_NODE_ID, mac_addr]]
asix_AX_CMD_READ_PHY_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_PHY_ID, array[int8, 2]]]
asix_AX_CMD_READ_MEDIUM_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MEDIUM_STATUS, int16]]
asix_AX_CMD_READ_MONITOR_MODE ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MONITOR_MODE, int8]]
asix_AX_CMD_READ_GPIOS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_GPIOS, int8]]
asix_AX_CMD_SW_PHY_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_SW_PHY_STATUS, int8]]
} [packed]
vusb_response_generic {
type flags[usb_request_types, int8]
req flags[usb_requests, int8]
len bytesize[data, int32]
data array[int8, 0:256]
} [packed]
usb_requests = USB_REQ_GET_STATUS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, USB_REQ_SET_ADDRESS, USB_REQ_GET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR, USB_REQ_GET_CONFIGURATION, USB_REQ_SET_CONFIGURATION, USB_REQ_GET_INTERFACE, USB_REQ_SET_INTERFACE, USB_REQ_SYNCH_FRAME, USB_REQ_SET_SEL, USB_REQ_SET_ISOCH_DELAY, USB_REQ_SET_ENCRYPTION, USB_REQ_GET_ENCRYPTION, USB_REQ_RPIPE_ABORT, USB_REQ_SET_HANDSHAKE, USB_REQ_RPIPE_RESET, USB_REQ_GET_HANDSHAKE, USB_REQ_SET_CONNECTION, USB_REQ_SET_SECURITY_DATA, USB_REQ_GET_SECURITY_DATA, USB_REQ_SET_WUSB_DATA, USB_REQ_LOOPBACK_DATA_WRITE, USB_REQ_LOOPBACK_DATA_READ, USB_REQ_SET_INTERFACE_DS, USB_REQ_GET_PARTNER_PDO, USB_REQ_GET_BATTERY_STATUS, USB_REQ_SET_PDO, USB_REQ_GET_VDM, USB_REQ_SEND_VDM
type vusb_response_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested by the kernel before the SET_CONFIGURATION request.
# TODO: figure out when is the USB_DT_OTG descriptor used.
# TODO: figure out when is the USB_DT_INTERFACE_ASSOCIATION descriptor used.
# TODO: figure out when is the USB_DT_BOS descriptor used.
type usb_string_descriptor_t[DATA] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_STRING, int8]
data DATA
} [packed]
usb_string_descriptor [
lang_id usb_string_descriptor_t[flags[usb_lang_ids, int16]]
string usb_string_descriptor_t[array[int8, 0:256]]
] [varlen]
usb_lang_ids = 0x436, 0x41c, 0x401, 0x801, 0xc01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001, 0x42b, 0x44d, 0x42c, 0x82c, 0x42d, 0x423, 0x445, 0x402, 0x455, 0x403, 0x404, 0x804, 0xc04, 0x1004, 0x1404, 0x41a, 0x405, 0x406, 0x413, 0x813, 0x409, 0x809, 0xc09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x425, 0x438, 0x429, 0x40b, 0x40c, 0x80c, 0xc0c, 0x100c, 0x140c, 0x180c, 0x437, 0x407, 0x807, 0xc07, 0x1007, 0x1407, 0x408, 0x447, 0x40d, 0x439, 0x40e, 0x40f, 0x421, 0x410, 0x810, 0x411, 0x44b, 0x860, 0x43f, 0x457, 0x412, 0x812, 0x426, 0x427, 0x827, 0x42f, 0x43e, 0x83e, 0x44c, 0x458, 0x44e, 0x861, 0x414, 0x814, 0x448, 0x415, 0x416, 0x816, 0x446, 0x418, 0x419, 0x44f, 0xc1a, 0x81a, 0x459, 0x41b, 0x424, 0x40a, 0x80a, 0xc0a, 0x100a, 0x140a, 0x180a, 0x1c0a, 0x200a, 0x240a, 0x280a, 0x2c0a, 0x300a, 0x340a, 0x380a, 0x3c0a, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a, 0x430, 0x441, 0x41d, 0x81d, 0x449, 0x444, 0x44a, 0x41e, 0x41f, 0x422, 0x420, 0x820, 0x443, 0x843, 0x42a, 0x4ff, 0xf0ff, 0xf4ff, 0xf8ff, 0xfcff
usb_qualifier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_QUALIFIER, int8]
bcdUSB flags[usb_versions, int16]
bDeviceClass int8
bDeviceSubClass int8
bDeviceProtocol int8
bMaxPacketSize0 flags[usb_device_max_packet_sizes, int8]
bNumConfigurations int8
bRESERVED const[0, int8]
} [packed]
usb_bos_descriptor {
bLength const[USB_DT_BOS_SIZE, int8]
bDescriptorType const[USB_DT_BOS, int8]
wTotalLength len[parent, int16]
bNumDeviceCaps len[caps, int8]
caps array[usb_dev_cap, 0:6]
} [packed]
usb_dev_cap [
generic usb_generic_cap_descriptor
wireless usb_wireless_cap_descriptor
ext_cap usb_ext_cap_descriptor
ss_cap usb_ss_cap_descriptor
ss_container_id usb_ss_container_id_descriptor
ssp_cap usb_ssp_cap_descriptor
ptm_cap usb_ptm_cap_descriptor
] [varlen]
usb_generic_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType flags[usb_capability_types, int8]
data array[int8, 0:256]
} [packed]
usb_capability_types = USB_CAP_TYPE_WIRELESS_USB, USB_CAP_TYPE_EXT, USB_SS_CAP_TYPE, USB_SSP_CAP_TYPE, CONTAINER_ID_TYPE, USB_PTM_CAP_TYPE
usb_wireless_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_WIRELESS_USB, int8]
bmAttributes flags[usb_wireless_cap_attributes, int8]
wPHYRates flags[usb_wireless_cap_phyrates, int16]
bmTFITXPowerInfo int8
bmFFITXPowerInfo int8
bmBandGroup int16
bReserved int8
} [packed]
usb_wireless_cap_attributes = USB_WIRELESS_P2P_DRD, USB_WIRELESS_BEACON_MASK, USB_WIRELESS_BEACON_SELF, USB_WIRELESS_BEACON_DIRECTED, USB_WIRELESS_BEACON_NONE
usb_wireless_cap_phyrates = USB_WIRELESS_PHY_53, USB_WIRELESS_PHY_80, USB_WIRELESS_PHY_107, USB_WIRELESS_PHY_160, USB_WIRELESS_PHY_200, USB_WIRELESS_PHY_320, USB_WIRELESS_PHY_400, USB_WIRELESS_PHY_480
usb_ext_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_EXT, int8]
bmAttributes1 flags[usb_ext_cap_attributes, int32:8]
bmAttributes2 int32:4
bmAttributes3 int32:4
bmAttributes4 int32:16
} [packed]
usb_ext_cap_attributes = USB_LPM_SUPPORT, USB_BESL_SUPPORT, USB_BESL_BASELINE_VALID, USB_BESL_DEEP_VALID
usb_ss_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SS_CAP_TYPE, int8]
bmAttributes flags[usb_ss_cap_attributes, int8]
wSpeedSupported flags[usb_ss_cap_speed, int16]
bFunctionalitySupport int8
bU1devExitLat int8
bU2DevExitLat int16
} [packed]
usb_ss_cap_attributes = USB_LTM_SUPPORT
usb_ss_cap_speed = USB_LOW_SPEED_OPERATION, USB_FULL_SPEED_OPERATION, USB_HIGH_SPEED_OPERATION, USB_5GBPS_OPERATION
usb_ss_container_id_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[CONTAINER_ID_TYPE, int8]
bReserved int8
ContainerID array[int8, 16]
} [packed]
usb_ssp_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SSP_CAP_TYPE, int8]
bReserved int8
bmAttributesSublinkSpeeds len[bmSublinkSpeedAttr, int32:5]
bmAttributesSpeedIDs int32:27
wFunctionalitySupport flags[usb_ssp_cap_funcs, int16]
wReserved int16
bmSublinkSpeedAttr array[flags[usb_ssp_cap_sublink_speeds, int32], 0:6]
} [packed]
usb_ssp_cap_funcs = USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, USB_SSP_MIN_RX_LANE_COUNT, USB_SSP_MIN_TX_LANE_COUNT
usb_ssp_cap_sublink_speeds = USB_SSP_SUBLINK_SPEED_SSID, USB_SSP_SUBLINK_SPEED_LSE, USB_SSP_SUBLINK_SPEED_ST, USB_SSP_SUBLINK_SPEED_RSVD, USB_SSP_SUBLINK_SPEED_LP, USB_SSP_SUBLINK_SPEED_LSM
usb_ptm_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_PTM_CAP_TYPE, int8]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Extra USB descriptors that come after an interface or an endpoint descriptor.
# TODO: consider removing class specific descriptors here for described classes.
usb_interface_extra_descriptor [
generic usb_generic_descriptor
hid_hid usb_hid_descriptor_hid
cdc_ecm usb_cdc_header_ecm
cdc_ncm usb_cdc_header_ncm
uac_control uac_control_iface_extra_descriptors
uac_as uac_as_iface_extra_descriptors
] [varlen]
usb_endpoint_extra_descriptor [
generic usb_generic_descriptor
uac_iso uac_iso_endpoint_descriptor
] [varlen]
usb_generic_descriptor {
bLength len[parent, int8]
bDescriptorType flags[usb_descriptor_types, int8]
data array[int8, 0:256]
} [packed]
usb_descriptor_types = USB_DT_DEVICE, USB_DT_CONFIG, USB_DT_STRING, USB_DT_INTERFACE, USB_DT_ENDPOINT, USB_DT_DEVICE_QUALIFIER, USB_DT_OTHER_SPEED_CONFIG, USB_DT_INTERFACE_POWER, USB_DT_OTG, USB_DT_DEBUG, USB_DT_INTERFACE_ASSOCIATION, USB_DT_SECURITY, USB_DT_KEY, USB_DT_ENCRYPTION_TYPE, USB_DT_BOS, USB_DT_DEVICE_CAPABILITY, USB_DT_WIRELESS_ENDPOINT_COMP, USB_DT_WIRE_ADAPTER, USB_DT_RPIPE, USB_DT_CS_RADIO_CONTROL, USB_DT_PIPE_USAGE, USB_DT_SS_ENDPOINT_COMP, USB_DT_SSP_ISOC_ENDPOINT_COMP, HID_DT_HID, HID_DT_REPORT, HID_DT_PHYSICAL
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested after the SET_CONFIGURATION request.
usb_hub_descriptor_hs {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
DeviceRemovable array[int8, USB_HUB_PORTS_BITS]
PortPwrCtrlMask array[int8, USB_HUB_PORTS_BITS]
} [packed]
usb_hub_descriptor_ss {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_SS_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
bHubHdrDecLat int8
wHubDelay int16
DeviceRemovable int16
} [packed]
define USB_HUB_PORTS_BITS ((USB_MAXCHILDREN + 1 + 7) / 8)
usb_hub_characteristics = HUB_CHAR_LPSM, HUB_CHAR_COMMON_LPSM, HUB_CHAR_INDV_PORT_LPSM, HUB_CHAR_NO_LPSM, HUB_CHAR_COMPOUND, HUB_CHAR_OCPM, HUB_CHAR_COMMON_OCPM, HUB_CHAR_INDV_PORT_OCPM, HUB_CHAR_NO_OCPM, HUB_CHAR_TTTT, HUB_CHAR_PORTIND
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Replies to USB control requests requested after the SET_CONFIGURATION request.
usb_port_status {
wPortStatus flags[usb_port_status_flags, int16]
wPortChange flags[usb_port_change_flags, int16]
dwExtPortStatus array[flags[usb_ext_port_status_flags, int32], 0:1]
} [packed]
usb_port_status_flags = USB_PORT_STAT_CONNECTION, USB_PORT_STAT_ENABLE, USB_PORT_STAT_SUSPEND, USB_PORT_STAT_OVERCURRENT, USB_PORT_STAT_RESET, USB_PORT_STAT_L1, USB_PORT_STAT_POWER, USB_PORT_STAT_LOW_SPEED, USB_PORT_STAT_HIGH_SPEED, USB_PORT_STAT_TEST, USB_PORT_STAT_INDICATOR, USB_PORT_STAT_LINK_STATE, USB_SS_PORT_STAT_POWER, USB_SS_PORT_STAT_SPEED, USB_PORT_STAT_SPEED_5GBPS, USB_SS_PORT_LS_U0, USB_SS_PORT_LS_U1, USB_SS_PORT_LS_U2, USB_SS_PORT_LS_U3, USB_SS_PORT_LS_SS_DISABLED, USB_SS_PORT_LS_RX_DETECT, USB_SS_PORT_LS_SS_INACTIVE, USB_SS_PORT_LS_POLLING, USB_SS_PORT_LS_RECOVERY, USB_SS_PORT_LS_HOT_RESET, USB_SS_PORT_LS_COMP_MOD, USB_SS_PORT_LS_LOOPBACK
usb_port_change_flags = USB_PORT_STAT_C_CONNECTION, USB_PORT_STAT_C_ENABLE, USB_PORT_STAT_C_SUSPEND, USB_PORT_STAT_C_OVERCURRENT, USB_PORT_STAT_C_RESET, USB_PORT_STAT_C_L1, USB_PORT_STAT_C_BH_RESET, USB_PORT_STAT_C_LINK_STATE, USB_PORT_STAT_C_CONFIG_ERROR
usb_ext_port_status_flags = USB_EXT_PORT_STAT_RX_SPEED_ID, USB_EXT_PORT_STAT_TX_SPEED_ID, USB_EXT_PORT_STAT_RX_LANES, USB_EXT_PORT_STAT_TX_LANES
usb_hub_status {
wHubStatus flags[usb_hub_status_flags, int16]
wHubChange flags[usb_hub_change_flags, int16]
} [packed]
usb_hub_status_flags = HUB_STATUS_LOCAL_POWER, HUB_STATUS_OVERCURRENT
usb_hub_change_flags = HUB_CHANGE_LOCAL_POWER, HUB_CHANGE_OVERCURRENT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# HID device class specific descriptions.
# https://www.usb.org/sites/default/files/documents/hid1_11.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/usbhid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/hid.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_hid.c
# Connected HID devices are known to create the following /dev/ files:
# /dev/hidraw#, /dev/usb/hiddev# and /dev/input/event#.
resource fd_usb_hid[fd_usb]
syz_usb_connect$hid(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_hid], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_hid (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$hid(fd fd_usb_hid, descs ptr[in, vusb_descriptors_hid], resps ptr[in, vusb_responses_hid]) (timeout[300], remote_cover)
# idVendor and idProduct are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor_hid {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 64, array[usb_config_descriptor_hid, 1]]
} [packed]
usb_config_descriptor_hid {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_hid, 1]]
} [packed]
usb_interface_descriptor_hid {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_HID, int8], const[USB_INTERFACE_SUBCLASS_BOOT, int8], flags[usb_hid_protocols, int8], usb_hid_descriptor_hid, usb_endpoint_descriptors_hid]
} [packed]
usb_hid_protocols = USB_INTERFACE_PROTOCOL_KEYBOARD, USB_INTERFACE_PROTOCOL_MOUSE
usb_endpoint_descriptors_hid {
in usb_endpoint_descriptor_hid_in
out array[usb_endpoint_descriptor_hid_out, 0:1]
} [packed]
usb_endpoint_descriptor_hid_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_IN_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_hid_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_OUT_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_HID_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_HID_IN_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_HID_OUT_ADDRESS (2)
vusb_descriptors_hid {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
# For unknown reasons these are requested as USB_TYPE_STANDARD and not as USB_TYPE_CLASS.
# Linux doesn't request HID_DT_HID, but some hosts might do that.
HID_DT_REPORT ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]]
HID_DT_HID ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_HID, usb_hid_descriptor_hid]]
} [packed]
vusb_responses_hid {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
HID_REQ_GET_REPORT ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_REPORT, array[int8, 0:256]]]
HID_REQ_GET_PROTOCOL ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_PROTOCOL, int8]]
} [packed]
# USB HID specifications allows for multiple report and physical descriptors
# to be present, but I don't see any support for them in the Linux kernel,
# except for a single report descriptor.
usb_hid_descriptor_hid {
bLength len[parent, int8]
bDescriptorType const[HID_DT_HID, int8]
bcdHID int16
bCountryCode int8
bNumDescriptors const[1, int8]
report_desc usb_hid_class_descriptor_report
} [packed]
usb_hid_class_descriptor_report {
bDescriptorType const[HID_DT_REPORT, int8]
wDescriptorLength int16[0:HID_MAX_DESCRIPTOR_SIZE]
} [packed]
# TODO: it's hard to describe the REPORT descriptor structure via syzkaller
# descriptions, so consider generating it in Go code.
# TODO: the length of REPORT descriptor must match the value in HID descriptor.
# TODO: there are vendor specific REPORT descriptor formats (Logitech HID++).
# Linux HID stack doesn't support long items.
hid_descriptor_report {
items array[hid_report_item_short]
} [packed]
type hid_report_item_short_012_t[TYPE, TAGS] {
bSize len[data, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 0:2]
} [packed]
type hid_report_item_short_4_t[TYPE, TAGS] {
bSize const[3, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 4]
} [packed]
type hid_report_item_short_t[TYPE, TAGS] [
item_012 hid_report_item_short_012_t[TYPE, TAGS]
item_4 hid_report_item_short_4_t[TYPE, TAGS]
] [varlen]
hid_report_item_short [
main hid_report_item_short_t[HID_ITEM_TYPE_MAIN, hid_report_item_main_tags]
global hid_report_item_short_t[HID_ITEM_TYPE_GLOBAL, hid_report_item_global_tags]
local hid_report_item_short_t[HID_ITEM_TYPE_LOCAL, hid_report_item_local_tags]
] [varlen]
hid_report_item_main_tags = HID_MAIN_ITEM_TAG_INPUT, HID_MAIN_ITEM_TAG_OUTPUT, HID_MAIN_ITEM_TAG_FEATURE, HID_MAIN_ITEM_TAG_BEGIN_COLLECTION, HID_MAIN_ITEM_TAG_END_COLLECTION
hid_report_item_global_tags = HID_GLOBAL_ITEM_TAG_USAGE_PAGE, HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT, HID_GLOBAL_ITEM_TAG_UNIT, HID_GLOBAL_ITEM_TAG_REPORT_SIZE, HID_GLOBAL_ITEM_TAG_REPORT_ID, HID_GLOBAL_ITEM_TAG_REPORT_COUNT, HID_GLOBAL_ITEM_TAG_PUSH, HID_GLOBAL_ITEM_TAG_POP
hid_report_item_local_tags = HID_LOCAL_ITEM_TAG_USAGE, HID_LOCAL_ITEM_TAG_USAGE_MINIMUM, HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX, HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM, HID_LOCAL_ITEM_TAG_STRING_INDEX, HID_LOCAL_ITEM_TAG_STRING_MINIMUM, HID_LOCAL_ITEM_TAG_STRING_MAXIMUM, HID_LOCAL_ITEM_TAG_DELIMITER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# PRINTER device class specific descriptions.
# https://www.usb.org/sites/default/files/usbprint11a021811.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/class/usblp.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/printer.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_printer.c
# Connected PRINTER devices are known to create the following /dev/ files:
# /dev/usb/lp#.
# TODO: write descriptions for those.
# drivers/usb/class/usblp.c
define USBLP_REQ_GET_ID 0x00
define USBLP_REQ_GET_STATUS 0x01
define USBLP_REQ_RESET 0x02
define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00
define USBLP_FIRST_PROTOCOL 1
define USBLP_LAST_PROTOCOL 3
resource fd_usb_printer[fd_usb]
syz_usb_connect$printer(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_printer], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_printer (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$printer(fd fd_usb_printer, descs ptr[in, vusb_descriptors_printer], resps ptr[in, vusb_responses_printer]) (timeout[300], remote_cover)
usb_device_descriptor_printer {
inner usb_device_descriptor_t[0, 0, 0, 0x525, 0xa4a8, 64, array[usb_config_descriptor_printer, 1]]
} [packed]
usb_config_descriptor_printer {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_printer, 1]]
} [packed]
usb_interface_descriptor_printer {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_PRINTER, int8], const[1, int8], int8[USBLP_FIRST_PROTOCOL:USBLP_LAST_PROTOCOL], void, usb_endpoint_descriptors_printer]
} [packed]
usb_endpoint_descriptors_printer {
in usb_endpoint_descriptor_printer_out
out array[usb_endpoint_descriptor_printer_in, 0:1]
} [packed]
usb_endpoint_descriptor_printer_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_OUT_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_printer_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_IN_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_PRINTER_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_PRINTER_OUT_ADDRESS (1)
define USB_ENDPOINT_PRINTER_IN_ADDRESS (2 | USB_DIR_IN)
vusb_descriptors_printer {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_printer {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USBLP_REQ_GET_ID ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_ID, usb_printer_get_id_response]]
USBLP_REQ_GET_STATUS ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_STATUS, int8]]
USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, int8]]
} [packed]
usb_printer_get_id_response {
length len[id, int16be]
id array[int8, 0:256]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC ECM (Ethernet) device class specific descriptions.
# https://www.usb.org/document-library/class-definitions-communication-devices-12
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ecm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/u_ether.c
# Connected CDC ECM devices are known to create usbN network interfaces.
# TODO: write descriptions for those.
resource fd_usb_cdc_ecm[fd_usb]
syz_usb_connect$cdc_ecm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ecm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ecm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ecm(fd fd_usb_cdc_ecm, descs ptr[in, vusb_descriptors_cdc_ecm], resps ptr[in, vusb_responses_cdc_ecm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ecm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ecm, 1]]
} [packed]
usb_config_descriptor_cdc_ecm {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_cdc_ecm, 1]]
} [packed]
# Per specification CDC ECM devices have two interfaces (control and data),
# but here we're merging them into one for simplicity since Linux supports that.
usb_interface_descriptor_cdc_ecm {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[2:3], const[USB_CLASS_COMM, int8], const[USB_CDC_SUBCLASS_ETHERNET, int8], const[USB_CDC_PROTO_NONE, int8], usb_cdc_header_ecm, usb_endpoint_descriptors_cdc_ecm]
} [packed]
usb_endpoint_descriptors_cdc_ecm {
notify array[usb_endpoint_descriptor_cdc_ecm_notify, 0:1]
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
usb_endpoint_descriptor_cdc_ecm_notify {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_IN_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_OUT_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_OUT_ADDRESS (3)
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L155
usb_cdc_header_ecm {
union usb_cdc_union_desc_t[0, 0]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
other array[usb_cdc_header_ecm_other, 0:6]
} [packed]
usb_cdc_header_ecm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
ncm usb_cdc_ncm_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
usb_cdc_header_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_HEADER_TYPE, int8]
bcdCDC int16
} [packed]
usb_cdc_call_mgmt_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_CALL_MANAGEMENT_TYPE, int8]
bmCapabilities flags[usb_cdc_call_mgmt_caps, int8]
bDataInterface int8
} [packed]
usb_cdc_call_mgmt_caps = USB_CDC_CALL_MGMT_CAP_CALL_MGMT, USB_CDC_CALL_MGMT_CAP_DATA_INTF
usb_cdc_acm_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ACM_TYPE, int8]
bmCapabilities flags[usb_cdc_acm_caps, int8]
} [packed]
usb_cdc_acm_caps = USB_CDC_COMM_FEATURE, USB_CDC_CAP_LINE, USB_CDC_CAP_BRK, USB_CDC_CAP_NOTIFY
type usb_cdc_union_desc_t[MASTER, SLAVE] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_UNION_TYPE, int8]
bMasterInterface0 const[MASTER, int8]
bSlaveInterface0 const[SLAVE, int8]
slave_interfaces array[int8, 0:6]
} [packed]
usb_cdc_country_functional_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_COUNTRY_TYPE, int8]
iCountryCodeRelDate int8
wCountyCode0 int16
country_codes array[int16, 0:6]
} [packed]
usb_cdc_network_terminal_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NETWORK_TERMINAL_TYPE, int8]
bEntityId int8
iName int8
bChannelIndex int8
bPhysicalInterface int8
} [packed]
usb_cdc_ether_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ETHERNET_TYPE, int8]
iMACAddress const[1, int8]
bmEthernetStatistics int32
wMaxSegmentSize int16
wNumberMCFilters int16
bNumberPowerFilters int8
} [packed]
usb_cdc_dmm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_DMM_TYPE, int8]
bcdVersion int16
wMaxCommand int16
} [packed]
usb_cdc_mdlm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_TYPE, int8]
bcdVersion int16
bGUID usb_cdc_ecm_mbm_guid
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L61
usb_cdc_ecm_mbm_guid {
id0 const[0x14f5e048ba817a3, int64]
id1 const[0x2a397ecbffc007a6, int64]
} [packed]
usb_cdc_mdlm_detail_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_DETAIL_TYPE, int8]
bGuidDescriptorType int8
bDetailData array[int8, 0:256]
} [packed]
usb_cdc_obex_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_OBEX_TYPE, int8]
bcdVersion int16
} [packed]
usb_cdc_ncm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NCM_TYPE, int8]
bcdNcmVersion int16
bmNetworkCapabilities flags[usb_cdc_ncm_ncaps, int8]
} [packed]
usb_cdc_ncm_ncaps = USB_CDC_NCM_NCAP_ETH_FILTER, USB_CDC_NCM_NCAP_NET_ADDRESS, USB_CDC_NCM_NCAP_ENCAP_COMMAND, USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE, USB_CDC_NCM_NCAP_CRC_MODE, USB_CDC_NCM_NCAP_NTB_INPUT_SIZE
usb_cdc_mbim_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_TYPE, int8]
bcdMBIMVersion int16
wMaxControlMessage int16
bNumberFilters int8
bMaxFilterSize int8
wMaxSegmentSize int16
bmNetworkCapabilities int8
} [packed]
usb_cdc_mbim_extended_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_EXTENDED_TYPE, int8]
bcdMBIMExtendedVersion int16
bMaxOutstandingCommandMessages int8
wMTU int16
} [packed]
vusb_descriptors_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
usb_cdc_ecm_mac {
# This is a UTF16 encoded string "424242424242".
data0 const[0x3400320034003200, int64be]
data1 const[0x3400320034003200, int64be]
data2 const[0x3400320034003200, int64be]
} [packed]
vusb_responses_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC NCM class specific descriptions.
# CDC NCM is based on CDC ECM, so some of the descriptions are reused.
# https://www.usb.org/document-library/network-control-model-devices-specification-v10-and-errata-and-adopters-agreement
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ncm.c
resource fd_usb_cdc_ncm[fd_usb]
syz_usb_connect$cdc_ncm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ncm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ncm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ncm(fd fd_usb_cdc_ncm, descs ptr[in, vusb_descriptors_cdc_ncm], resps ptr[in, vusb_responses_cdc_ncm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ncm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ncm, 1]]
} [packed]
usb_config_descriptor_cdc_ncm {
inner usb_config_descriptor_t[const[1, int8], const[2, int8], usb_interface_descriptors_cdc_ncm]
} [packed]
usb_interface_descriptors_cdc_ncm {
control usb_interface_descriptor_fixed_t[0, CDC_NCM_COMM_ALTSETTING_NCM, 1, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, usb_cdc_header_ncm, usb_endpoint_descriptor_cdc_ecm_notify]
data_nop usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, void]
data usb_interface_descriptor_fixed_t[1, CDC_NCM_DATA_ALTSETTING_NCM, 2, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, usb_endpoint_descriptors_cdc_ncm_data]
} [packed]
usb_endpoint_descriptors_cdc_ncm_data {
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ncm.c#L798
usb_cdc_header_ncm {
union usb_cdc_union_desc_t[0, 1]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
ncm usb_cdc_ncm_desc
other array[usb_cdc_header_ncm_other, 0:6]
} [packed]
usb_cdc_header_ncm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
vusb_descriptors_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
vusb_responses_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_CDC_GET_NTB_PARAMETERS ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_PARAMETERS, usb_cdc_ncm_ntb_parameters]]
USB_CDC_GET_NTB_INPUT_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_INPUT_SIZE, int32]]
USB_CDC_GET_NTB_FORMAT ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_FORMAT, int16[0:1]]]
USB_CDC_GET_MAX_DATAGRAM_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_MAX_DATAGRAM_SIZE, int16]]
USB_CDC_GET_CRC_MODE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_CRC_MODE, int16[0:1]]]
} [packed]
usb_cdc_ncm_ntb_parameters {
wLength int16
bmNtbFormatsSupported int16
dwNtbInMaxSize int32
wNdpInDivisor int16
wNdpInPayloadRemainder int16
wNdpInAlignment int16
wPadding1 int16
dwNtbOutMaxSize int32
wNdpOutDivisor int16
wNdpOutPayloadRemainder int16
wNdpOutAlignment int16
wNtbOutMaxDatagrams int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC1 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1_legacy.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
# TODO: find out which /dev/ files are created by connected UAC1 devices and add descriptions for those.
resource fd_usb_uac1[fd_usb]
syz_usb_connect$uac1(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac1], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac1 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac1(fd fd_usb_uac1, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac1 {
inner usb_device_descriptor_t[0, 0, 0, 0x1d6b, 0x101, 64, array[usb_config_descriptor_uac1, 1]]
} [packed]
usb_config_descriptor_uac1 {
inner usb_config_descriptor_t[const[1, int8], const[3, int8], usb_interface_descriptors_uac1]
} [packed]
# TODO: control interface might have and optional interrupt endpoint.
usb_interface_descriptors_uac1 {
inner usb_interface_descriptors_uac1_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac1_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, 0, uac_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC uses IDs to make it possible for terminals and units to refer to each other.
# We don't have a way to describe this, so just use a limited number of ids.
type uac_id int8[1:6]
uac_control_iface_extra_descriptors {
header uac1_ac_header_descriptor
others array[uac_control_iface_extra_descriptor, 0:6]
} [packed]
uac1_ac_header_descriptor {
bLength const[UAC_DT_AC_HEADER_LENGTH, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdADC int16
wTotalLength len[uac_control_iface_extra_descriptors, int16]
bInCollection const[F_AUDIO_NUM_INTERFACES, int8]
# These must match interfaces numbers.
baInterfaceNr0 const[1, int8]
baInterfaceNr1 const[2, int8]
} [packed]
uac_control_iface_extra_descriptor [
input_terminal uac_input_terminal_descriptor
output_terminal uac1_output_terminal_descriptor
mixer_unit uac_mixer_unit_descriptor
selector_unit uac_selector_unit_descriptor
feature_unit uac_feature_unit_descriptor
processing_unit uac_processing_unit_descriptor
extension_unit uac_extension_unit_descriptor
] [varlen]
define F_AUDIO_NUM_INTERFACES 2
define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
uac_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bNrChannels int8
wChannelConfig int16
iChannelNames int8
iTerminal int8
} [packed]
# The following list contains input terminal types and inout terminal types.
uac_input_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_INPUT_TERMINAL_UNDEFINED, UAC_INPUT_TERMINAL_MICROPHONE, UAC_INPUT_TERMINAL_DESKTOP_MICROPHONE, UAC_INPUT_TERMINAL_PERSONAL_MICROPHONE, UAC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE, UAC_INPUT_TERMINAL_MICROPHONE_ARRAY, UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
# The following list contains output terminal types and inout terminal types.
uac_output_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_OUTPUT_TERMINAL_UNDEFINED, UAC_OUTPUT_TERMINAL_SPEAKER, UAC_OUTPUT_TERMINAL_HEADPHONES, UAC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO, UAC_OUTPUT_TERMINAL_DESKTOP_SPEAKER, UAC_OUTPUT_TERMINAL_ROOM_SPEAKER, UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER, UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
uac1_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
iTerminal int8
} [packed]
uac_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_selector_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_SELECTOR_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bControlSize len[bmaControls, int8]
bmaControls array[flags[uac_feature_unit_controls, int16], 1:6]
iFeature int8
} [packed]
uac_feature_unit_controls = UAC_FU_MUTE, UAC_FU_VOLUME, UAC_FU_BASS, UAC_FU_MID, UAC_FU_TREBLE, UAC_FU_GRAPHIC_EQUALIZER, UAC_FU_AUTOMATIC_GAIN, UAC_FU_DELAY, UAC_FU_BASS_BOOST, UAC_FU_LOUDNESS
uac_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_PROCESSING_UNIT, int8]
bUnitID uac_id
wProcessType flags[uac_processing_unit_types, int16]
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_processing_unit_types = UAC_PROCESS_UNDEFINED, UAC_PROCESS_UP_DOWNMIX, UAC_PROCESS_DOLBY_PROLOGIC, UAC_PROCESS_STEREO_EXTENDER, UAC_PROCESS_REVERB, UAC_PROCESS_CHORUS, UAC_PROCESS_DYN_RANGE_COMP
uac_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_EXTENSION_UNIT, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_iface_extra_descriptors {
others array[uac_as_iface_extra_descriptor, 0:6]
} [packed]
uac_as_iface_extra_descriptor [
as_header uac1_as_header_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
format_type_i_ext uac_format_type_i_ext_descriptor
] [varlen]
uac1_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bDelay int8
wFormatTag flags[uac_format_tags, int16]
} [packed]
uac_format_tags = UAC_FORMAT_TYPE_I_UNDEFINED, UAC_FORMAT_TYPE_I_PCM, UAC_FORMAT_TYPE_I_PCM8, UAC_FORMAT_TYPE_I_IEEE_FLOAT, UAC_FORMAT_TYPE_I_ALAW, UAC_FORMAT_TYPE_I_MULAW, UAC_FORMAT_TYPE_II_MPEG, UAC_FORMAT_TYPE_II_AC3
uac_usb_format_types_i = UAC_FORMAT_TYPE_I, UAC_FORMAT_TYPE_II, UAC_FORMAT_TYPE_III, UAC_FORMAT_TYPE_UNDEFINED
uac_format_type_i_continuous_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tLowerSamFreq array[int8, 0:3]
tUpperSamFreq array[int8, 0:3]
} [packed]
uac_format_type_i_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
uac_format_type_ii_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
uac_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
define USB_ENDPOINT_UAC1_AS_OUT_ADDRESS (1 | USB_DIR_OUT)
define USB_ENDPOINT_UAC1_AS_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_UAC1_AS_ATTRIBUTES (USB_ENDPOINT_SYNC_ADAPTIVE | USB_ENDPOINT_XFER_ISOC)
uac_iso_ep_attributes = USB_ENDPOINT_SYNCTYPE, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC
uac_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC_EP_GENERAL, int8]
bmAttributes flags[uac_iso_ep_attributes, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
vusb_descriptors_uac1 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_uac1 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
audio_UAC_GET_CUR ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_CUR, array[int8, 1:3]]]
audio_UAC_GET_MIN ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MIN, array[int8, 1:3]]]
audio_UAC_GET_MAX ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MAX, array[int8, 1:3]]]
audio_UAC_GET_RES ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_RES, array[int8, 1:4]]]
audio_UAC_GET_MEM ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MEM, array[int8, 3]]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC2 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac2.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac2[fd_usb]
syz_usb_connect$uac2(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac2], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac2 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac2(fd fd_usb_uac2, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac2 {
inner usb_device_descriptor_t[0, 0, 0, 0x41e, 0x3000, 64, array[usb_config_descriptor_uac2, 1]]
} [packed]
usb_config_descriptor_uac2 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac2_interface_assoc_descriptor, usb_interface_descriptors_uac2]
} [packed]
uac2_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[audio_function_category_types, int8]
bFunctionProtocol const[UAC_VERSION_2, int8]
iFunction int8
} [packed]
audio_function_category_types = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER
usb_interface_descriptors_uac2 {
inner usb_interface_descriptors_uac2_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac2_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_2, uac2_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptors {
header uac2_ac_header_descriptor
others array[uac2_control_iface_extra_descriptor, 0:6]
} [packed]
uac2_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bcdADC int16
bCategory flags[uac2_feature_unit_controls, int8]
wTotalLength len[uac2_control_iface_extra_descriptors, int16]
bmControls int8
} [packed]
uac2_feature_unit_controls = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER, uac_feature_unit_controls
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_as_iface_extra_descriptors {
others array[uac2_as_iface_extra_descriptor, 0:6]
} [packed]
uac2_as_iface_extra_descriptor [
as_header uac2_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
uac2_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int8
bFormatType flags[uac_usb_format_types_i, int8]
bmFormats flags[uac_format_tags, int32]
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
} [packed]
b_sub_slot_sizes = 1, 2, 3, 4
uac2_format_type_i_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize flags[b_sub_slot_sizes, int8]
bBitResolution int8
} [packed]
uac2_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac_format_type_ii_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bHeaderLength int8
bSideBandProtocol int8
} [packed]
uac_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac2_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubtype const[UAC_EP_GENERAL, int8]
bmAttributes flags[csep_bm_attributes, int8]
bmControls flags[csep_bm_controls, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
csep_bm_attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, UAC_EP_CS_ATTR_PITCH_CONTROL, UAC_EP_CS_ATTR_FILL_MAX
csep_bm_controls = UAC2_CONTROL_PITCH, UAC2_CONTROL_DATA_OVERRUN, UAC2_CONTROL_DATA_UNDERRUN
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptor [
input_terminal uac2_input_terminal_descriptor
output_terminal uac2_output_terminal_descriptor
mixer_unit uac2_mixer_unit_descriptor
selector_unit uac2_clock_selector_descriptor
feature_unit uac2_feature_unit_descriptor
processing_unit uac2_processing_unit_descriptor
extension_unit uac2_extension_unit_descriptor
effect_unit uac2_effect_unit_descriptor
sample_rate uac2_sample_rate_descriptor
source_unit uac2_clock_source_descriptor
multiply_unit uac2_clock_multiplier_descriptor
] [varlen]
uac2_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
bmControls int8
iTerminal int8
} [packed]
uac2_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal int8
bSourceID uac_id
bCSourceID int8
bmControls int16
iTerminal int8
} [packed]
uac2_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Figure out if bmControls and iClockSelector should be a part of this structure.
uac2_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
# TODO: Verify coverage.
uac2_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_PROCESSING_UNIT_V2, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_processing_unit_types = UAC2_PROCESS_UNDEFINED, UAC2_PROCESS_UP_DOWNMIX, UAC2_PROCESS_DOLBY_PROLOCIC, UAC2_PROCESS_STEREO_EXTENDER
uac2_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_EXTENSION_UNIT_V2, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Verify coverage.
uac2_effect_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_EFFECT_UNIT, int8]
bUnitID uac_id
wEffectType flags[uac2_effect_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_effect_unit_types = UAC2_EFFECT_UNDEFINED, UAC2_EFFECT_PARAM_EQ, UAC2_EFFECT_REVERB, UAC2_EFFECT_MOD_DELAY, UAC2_EFFECT_DYN_RANGE_COMP
uac2_sample_rate_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_SAMPLE_RATE_CONVERTER, int8]
bUnitID uac_id
wProcessType flags[uac2_processing_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_feature_unit_controls, int16], 1:6]
} [packed]
uac2_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac2_clock_bmattribute_types, int8]
bmControls int8
bAssocTerminal int8
iClockSource flags[uac2_clock_source_types, int8]
} [packed]
uac2_clock_bmattribute_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_source_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int8
iClockMultiplier int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC3 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac3.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac3[fd_usb]
syz_usb_connect$uac3(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac3], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac3 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac3(fd fd_usb_uac3, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac3 {
inner usb_device_descriptor_t[0, 0, 0, 0x582, 0x582, 64, array[usb_config_descriptor_uac3, 1]]
} [packed]
usb_config_descriptor_uac3 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac3_interface_assoc_descriptor, usb_interface_descriptors_uac3]
} [packed]
uac3_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[uac3_all_subclasses, int8]
bFunctionProtocol const[UAC_VERSION_3, int8]
iFunction int8
} [packed]
usb_interface_descriptors_uac3 {
inner usb_interface_descriptors_uac3_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac3_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_3, uac3_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptors {
header uac3_ac_header_descriptor
others array[uac3_control_iface_extra_descriptor, 0:6]
} [packed]
uac3_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bCategory flags[uac3_feature_unit_controls, int8]
wTotalLength len[uac3_control_iface_extra_descriptors, int16]
bmControls int32
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_as_iface_extra_descriptors {
others array[uac3_as_iface_extra_descriptor, 0:6]
} [packed]
uac3_as_iface_extra_descriptor [
as_header uac3_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
# TODO: Figure out how wClusterDescrID is used in the kernel.
uac3_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int32
wClusterDescrID int16
bmFormats flags[uac_format_tags, int64]
bSubslotSize int8
bBitResolution int8
bmAuxProtocols int16
bControlSize int8
} [packed]
uac3_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC3_CS_ENDPOINT, int8]
bmControls int32
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptor [
input_terminal uac3_input_terminal_descriptor
output_terminal uac3_output_terminal_descriptor
mixer_unit uac3_mixer_unit_descriptor
selector_unit uac3_clock_selector_descriptor
source_unit uac3_clock_source_descriptor
multiply_unit uac3_clock_multiplier_descriptor
feature_unit uac3_feature_unit_descriptor
processing_unit uac3_processing_unit_descriptor
extension_unit uac3_extension_unit_descriptor
power_domain uac3_power_domain_descriptor
cluster_info_segment uac3_cluster_information_segment_descriptor
# Only cluster information segment is currently used in the kernel.See: sound/usb/stream.c
# cluster_segment uac3_cluster_segment_descriptor
# cluster_end_segment uac3_cluster_end_segment_descriptor
# The following units are not yet supported by the kernel.
# See audio_validators[] in sound/usb/validate.c:
# effect_unit uac3_effect_unit_descriptor
# sample_rate uac3_sample_rate_descriptor
# connectors_unit uac3_connectors_unit_descriptor
# extended_term_unit uac3_extended_terminal_unit
] [varlen]
uac3_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bmControls int32
wClusterDescrID int16
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
bCSourceID int8
bmControls int32
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac3_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
uac3_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac3_clock_bmattribute_types, int8]
bmControls int32
bReferenceTerminal int8
wClockSourceStr int16
} [packed]
uac3_clock_bmattribute_types = UAC3_CLOCK_SOURCE_TYPE_EXT, UAC3_CLOCK_SOURCE_TYPE_INT, UAC3_CLOCK_SOURCE_ASYNC, UAC3_CLOCK_SOURCE_SYNCED_TO_SOF
uac3_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int32
wCMultiplierDescrStr int16
} [packed]
uac3_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_feature_unit_controls, int32], 1:6]
} [packed]
uac3_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_PROCESSING_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_processing_unit_types = UAC3_PROCESS_UNDEFINED, UAC3_PROCESS_UP_DOWNMIX, UAC3_PROCESS_STEREO_EXTENDER, UAC3_PROCESS_MULTI_FUNCTION
uac3_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_EXTENSION_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_power_domain_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_POWER_DOMAIN, int8]
bPowerDomainID int8
waRecoveryTime1 int16
waRecoveryTime2 int16
bNrEntities int8
baEntityID array[int8, 0:8]
} [packed]
uac3_cluster_information_segment_descriptor {
bLength len[parent, int16]
bSegmentType const[UAC3_CHANNEL_INFORMATION, int8]
bChPurpose flags[uac3_cluster_channel_purposes, int8]
bChRelationship flags[uac3_cluster_channel_relationships, int8]
bChGroupID int8
} [packed]
uac3_cluster_channel_purposes = UAC3_PURPOSE_UNDEFINED, UAC3_PURPOSE_GENERIC_AUDIO, UAC3_PURPOSE_VOICE, UAC3_PURPOSE_SPEECH, UAC3_PURPOSE_AMBIENT, UAC3_PURPOSE_REFERENCE, UAC3_PURPOSE_ULTRASONIC, UAC3_PURPOSE_VIBROKINETIC, UAC3_PURPOSE_NON_AUDIO
uac3_cluster_channel_relationships = UAC3_CH_RELATIONSHIP_UNDEFINED, UAC3_CH_MONO, UAC3_CH_LEFT, UAC3_CH_RIGHT, UAC3_CH_ARRAY, UAC3_CH_PATTERN_X, UAC3_CH_PATTERN_Y, UAC3_CH_PATTERN_A, UAC3_CH_PATTERN_B, UAC3_CH_PATTERN_M, UAC3_CH_PATTERN_S, UAC3_CH_FRONT_LEFT, UAC3_CH_FRONT_RIGHT, UAC3_CH_FRONT_CENTER, UAC3_CH_FRONT_LEFT_OF_CENTER, UAC3_CH_FRONT_RIGHT_OF_CENTER, UAC3_CH_FRONT_WIDE_LEFT, UAC3_CH_FRONT_WIDE_RIGHT, UAC3_CH_SIDE_LEFT, UAC3_CH_SIDE_RIGHT, UAC3_CH_SURROUND_ARRAY_LEFT, UAC3_CH_SURROUND_ARRAY_RIGHT, UAC3_CH_BACK_LEFT, UAC3_CH_BACK_RIGHT, UAC3_CH_BACK_CENTER, UAC3_CH_BACK_LEFT_OF_CENTER, UAC3_CH_BACK_RIGHT_OF_CENTER, UAC3_CH_BACK_WIDE_LEFT, UAC3_CH_BACK_WIDE_RIGHT, UAC3_CH_TOP_CENTER, UAC3_CH_TOP_FRONT_LEFT, UAC3_CH_TOP_FRONT_RIGHT, UAC3_CH_TOP_FRONT_CENTER, UAC3_CH_TOP_FRONT_LOC, UAC3_CH_TOP_FRONT_ROC, UAC3_CH_TOP_FRONT_WIDE_LEFT, UAC3_CH_TOP_FRONT_WIDE_RIGHT, UAC3_CH_TOP_SIDE_LEFT, UAC3_CH_TOP_SIDE_RIGHT, UAC3_CH_TOP_SURR_ARRAY_LEFT, UAC3_CH_TOP_SURR_ARRAY_RIGHT, UAC3_CH_TOP_BACK_LEFT, UAC3_CH_TOP_BACK_RIGHT, UAC3_CH_TOP_BACK_CENTER, UAC3_CH_TOP_BACK_LOC, UAC3_CH_TOP_BACK_ROC, UAC3_CH_TOP_BACK_WIDE_LEFT, UAC3_CH_TOP_BACK_WIDE_RIGHT, UAC3_CH_BOTTOM_CENTER, UAC3_CH_BOTTOM_FRONT_LEFT, UAC3_CH_BOTTOM_FRONT_RIGHT, UAC3_CH_BOTTOM_FRONT_CENTER, UAC3_CH_BOTTOM_FRONT_LOC, UAC3_CH_BOTTOM_FRONT_ROC, UAC3_CH_BOTTOM_FRONT_WIDE_LEFT, UAC3_CH_BOTTOM_FRONT_WIDE_RIGHT, UAC3_CH_BOTTOM_SIDE_LEFT, UAC3_CH_BOTTOM_SIDE_RIGHT, UAC3_CH_BOTTOM_SURR_ARRAY_LEFT, UAC3_CH_BOTTOM_SURR_ARRAY_RIGHT, UAC3_CH_BOTTOM_BACK_LEFT, UAC3_CH_BOTTOM_BACK_RIGHT, UAC3_CH_BOTTOM_BACK_CENTER, UAC3_CH_BOTTOM_BACK_LOC, UAC3_CH_BOTTOM_BACK_ROC, UAC3_CH_BOTTOM_BACK_WIDE_LEFT, UAC3_CH_BOTTOM_BACK_WIDE_RIGHT, UAC3_CH_LOW_FREQUENCY_EFFECTS, UAC3_CH_LFE_LEFT, UAC3_CH_LFE_RIGHT, UAC3_CH_HEADPHONE_LEFT, UAC3_CH_HEADPHONE_RIGHT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# This list consists of uac3_func_subclasses + uac3_badd_classes.
uac3_all_subclasses = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0, UAC3_FUNCTION_SUBCLASS_GENERIC_IO, UAC3_FUNCTION_SUBCLASS_HEADPHONE, UAC3_FUNCTION_SUBCLASS_SPEAKER, UAC3_FUNCTION_SUBCLASS_MICROPHONE, UAC3_FUNCTION_SUBCLASS_HEADSET, UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE
uac3_feature_unit_controls = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_DESKTOP_SPEAKER, UAC3_FUNCTION_HOME_THEATER, UAC3_FUNCTION_MICROPHONE, UAC3_FUNCTION_HEADSET, UAC3_FUNCTION_TELEPHONE, UAC3_FUNCTION_CONVERTER, UAC3_FUNCTION_SOUND_RECORDER, UAC3_FUNCTION_IO_BOX, UAC3_FUNCTION_MUSICAL_INSTRUMENT, UAC3_FUNCTION_PRO_AUDIO, UAC3_FUNCTION_AUDIO_VIDEO, UAC3_FUNCTION_CONTROL_PANEL, UAC3_FUNCTION_HEADPHONE, UAC3_FUNCTION_GENERIC_SPEAKER, UAC3_FUNCTION_HEADSET_ADAPTER, UAC3_FUNCTION_SPEAKERPHONE, UAC3_FUNCTION_OTHER
# TODO: Support uac3 badd profiles. See sound/usb/mixer.c: snd_usb_mixer_controls_badd()
# uac3_badd_endpoint_descriptor {
# inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
# } [packed]
#uac3_badd_maxsizes = UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# MIDI device class specific descriptions.
# https://www.usb.org/sites/default/files/midi10.pdf
# https://elixir.bootlin.com/linux/latest/source/sound/usb/midi.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_midi.c
syz_usb_connect$midi(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_midi], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
usb_device_descriptor_midi {
inner usb_device_descriptor_t[0, 0, 0, 0x1430, 0x474b, 64, array[usb_config_descriptor_midi, 1]]
} [packed]
usb_config_descriptor_midi {
inner usb_config_descriptor_t[const[1, int8], const[1, int8], usb_interface_descriptors_midi]
} [packed]
usb_interface_descriptors_midi {
inner usb_interface_descriptors_midi_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_midi_inner {
control usb_interface_descriptor_eps_array_t[const[0, int8], const[0, int8], const[USB_CLASS_AUDIO, int8], const[USB_SUBCLASS_MIDISTREAMING, int8], flags[uac_version_types, int8], array[usb_midi_iface_extra], array[usb_endpoint_descriptor_midi, 0:8]]
} [packed]
usb_endpoint_descriptor_midi {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], usb_ms_endpoint_descriptor]
} [packed]
midi_jack_type = USB_MS_EMBEDDED, USB_MS_EXTERNAL
uac_version_types = UAC_VERSION_1, UAC_VERSION_2, UAC_VERSION_3
usb_ms_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[USB_MS_GENERAL, int8]
bNumEmbMIDIJack len[baAssocJackID, int8]
baAssocJackID array[int8, 0:16]
} [packed]
usb_midi_iface_extra [
ms_header usb_ms_header_descriptor
midi_in_jack usb_midi_in_jack_descriptor
midi_out_jack usb_midi_out_jack_descriptor
] [varlen]
usb_ms_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdMSC int16
wTotalLength len[parent, int16]
} [packed]
usb_midi_in_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_IN_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
iJack int8
} [packed]
usb_midi_out_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_OUT_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
bNrInputPins len[pins, int8]
pins array[usb_midi_source_pin]
iJack int8
} [packed]
usb_midi_source_pin {
baSourceID int8
baSourcePin int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# ath9k driver specific descriptions.
include <drivers/net/wireless/ath/ath9k/htc_hst.h>
include <drivers/net/wireless/ath/ath9k/hif_usb.h>
define USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS (1)
define USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_IN_ADDRESS (3 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS (4)
define USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS (5)
define USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS (6)
resource fd_usb_ath9k[fd_usb]
syz_usb_connect_ath9k(speed const[USB_SPEED_HIGH], dev_len len[dev], dev ptr[in, usb_device_descriptor_ath9k], conn_descs const[0]) fd_usb_ath9k (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_ep_write$ath9k_ep1(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS], len bytesize[data], data ptr[in, ath9k_bulk_frame]) (timeout[300], remote_cover)
syz_usb_ep_write$ath9k_ep2(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS], len bytesize[data], data ptr[in, htc_frame]) (timeout[300], remote_cover)
usb_device_descriptor_ath9k {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xcf3, 0x9271, 0x108, array[usb_config_descriptor_ath9k, 1]]
} [packed]
usb_config_descriptor_ath9k {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_ath9k]
} [packed]
usb_interface_descriptor_ath9k {
iface usb_interface_descriptor_fixed_t[0, 0, 6, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_ath9k]
} [packed]
usb_endpoint_descriptors_ath9k {
bulk_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
int_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
bulk_extra1 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_extra2 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
} [packed]
define USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_ATH9K_INT_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
ath9k_bulk_frame {
packets array[ath9k_bulk_packet]
} [packed]
ath9k_bulk_packet {
pkt_len len[data, int16]
pkt_tag const[ATH_USB_RX_STREAM_MODE_TAG, int16]
data array[int8]
} [packed, align[4]]
htc_frame [
ready htc_ready_frame
conn_svc_rsp htc_conn_svc_rsp_frame
generic htc_generic_frame
] [varlen]
# This is actually wrong, as the driver is buggy and doesn't skip the header
# before processing the frame payload, but let's leave it like thise for now.
htc_ready_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_ready_msg
} [packed]
htc_ready_msg {
message_id const[HTC_MSG_READY_ID, int16be]
credits int16be
credit_size int16be
max_endpoints int8
pad int8
} [packed]
htc_conn_svc_rsp_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_conn_svc_rspmsg
} [packed]
htc_conn_svc_rspmsg {
message_id const[HTC_MSG_CONNECT_SERVICE_RESPONSE_ID, int16be]
service_id flags[htc_svcs, int16be]
status const[HTC_SERVICE_SUCCESS, int8]
endpoint_id int8
max_msg_len int16be
svc_meta_len int8
pad int8
} [packed]
htc_svcs = HTC_CTRL_RSVD_SVC, HTC_LOOPBACK_RSVD_SVC, WMI_CONTROL_SVC, WMI_BEACON_SVC, WMI_CAB_SVC, WMI_UAPSD_SVC, WMI_MGMT_SVC, WMI_DATA_VO_SVC, WMI_DATA_VI_SVC, WMI_DATA_BE_SVC, WMI_DATA_BE_SVC
htc_generic_frame {
endpoint_id int8[0:8]
flags flags[htc_frame_flags, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload array[int8, 0:256]
} [packed]
htc_frame_flags = HTC_FLAGS_RECV_TRAILER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Assorted driver-specific descriptions of generic syz_* calls' variants.
# Generic calls such as syz_usb_connect() and syz_usb_control_io() should be enough
# (in theory) to emulate a proper device and finish driver probes without a hitch.
# However, there are cases when syzkaller fails to come up with correct inputs to achieve it.
# Use fixed descriptors to quickly pass through probe() to access select drivers' post-probe functionality.
# It is important to note that, one way or another, drivers in question require multiple control requests
# between a driver and a device processed during probe(). Descriptions below do not deal with specific
# CTRL requests as such (except for basic information included in vusb_responses_XXX). Instead, rely on
# seeds, created both manually and with syzkaller's help. For examples, see sys/linux/test/vusb_XXX.
# Common constants for endpoint descriptors.
define USB_ENDPOINT_BULK_ATTR (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_INT_ATTR (USB_ENDPOINT_XFER_INT)
define USB_FIXED_ENDPOINT_BULK_IN_ADDR (1 | USB_DIR_IN)
define USB_FIXED_ENDPOINT_BULK_OUT_ADDR (2)
define USB_FIXED_ENDPOINT_INT_IN_ADDR (3 | USB_DIR_IN)
define USB_RECIP_DEVICE 0x00
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# rtl8150 driver specific descriptions.
resource fd_usb_rtl8150[fd_usb]
syz_usb_connect$rtl8150(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_rtl8150], conn_descs const[0]) fd_usb_rtl8150 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$rtl8150(fd fd_usb_rtl8150, descs ptr[in, vusb_descriptors_rtl8150], resps ptr[in, vusb_responses_rtl8150]) (timeout[300], remote_cover)
usb_device_descriptor_rtl8150 {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xbda, 0x8150, 0, array[usb_config_descriptor_rtl8150, 1]]
} [packed]
usb_config_descriptor_rtl8150 {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_rtl8150]
} [packed]
usb_interface_descriptor_rtl8150 {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_rtl8150]
} [packed]
usb_endpoint_descriptors_rtl8150 {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
RTL8150_REQ_GET_REGS ptr[in, vusb_response_t[RTL8150_REQT_READ, RTL8150_REQ_GET_REGS, array[int8, 0:6]]]
RTL8150_REQ_SET_REGS ptr[in, vusb_response_t[RTL8150_REQT_WRITE, RTL8150_REQ_SET_REGS, array[int8, 0:6]]]
} [packed]
define RTL8150_REQ_GET_REGS 0x05
define RTL8150_REQ_SET_REGS 0x05
define RTL8150_REQT_READ 0xc0
define RTL8150_REQT_WRITE 0x40
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# sierra_net driver specific descriptions.
resource fd_usb_sierra_net[fd_usb]
syz_usb_connect$sierra_net(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_sierra_net], conn_descs const[0]) fd_usb_sierra_net (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$sierra_net(fd fd_usb_sierra_net, descs ptr[in, vusb_descriptors_sierra_net], resps ptr[in, vusb_responses_sierra_net]) (timeout[300], remote_cover)
usb_device_descriptor_sierra_net {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x1199, 0x68a3, 0, array[usb_config_descriptor_sierra_net, 1]]
} [packed]
usb_config_descriptor_sierra_net {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_sierra_net]
} [packed]
usb_interface_descriptor_sierra_net {
iface usb_interface_descriptor_fixed_t[7, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_sierra_net]
} [packed]
# sierra_net driver does not expect fixed ep addresses, so refrain from being too specific here.
# As long as we ensure there are 3 endpoints, 2 bulk and 1 int, syzkaller should figure it out.
usb_endpoint_descriptors_sierra_net {
bulk_in usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
bulk_out usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
status usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_INT_ATTR, int8], void]
} [packed]
vusb_descriptors_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_CDC_GET_ENCAPSULATED_RESPONSE ptr[in, vusb_response_t[SIERRA_CMD_TYPE_IN, USB_CDC_GET_ENCAPSULATED_RESPONSE, array[int8, 1024]]]
USB_CDC_SEND_ENCAPSULATED_COMMANDT ptr[in, vusb_response_t[SIERRA_CMD_TYPE_OUT, USB_CDC_SEND_ENCAPSULATED_COMMAND, array[int8, 0:4]]]
} [packed]
define SIERRA_CMD_TYPE_IN (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
define SIERRA_CMD_TYPE_OUT (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# lan78xx driver specific descriptions.
# While these syz_* variants noticably help with the probe() process, they are not enough.
# This is due to a high number of control requests expected between the driver and the device.
include <drivers/net/usb/smsc95xx.h>
resource fd_usb_lan78xx[fd_usb]
syz_usb_connect$lan78xx(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_lan78xx], conn_descs const[0]) fd_usb_lan78xx (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$lan78xx(fd fd_usb_lan78xx, descs ptr[in, vusb_descriptors_lan78xx], resps ptr[in, vusb_responses_lan78xx]) (timeout[300], remote_cover)
usb_device_descriptor_lan78xx {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x424, 0x7850, 0, array[usb_config_descriptor_lan78xx, 1]]
} [packed]
usb_config_descriptor_lan78xx {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_lan78xx]
} [packed]
usb_interface_descriptor_lan78xx {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_lan78xx]
} [packed]
usb_endpoint_descriptors_lan78xx {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_VENDOR_REQUEST_READ_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_READ_REGISTER, int32]]
USB_VENDOR_REQUEST_WRITE_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_OUT, USB_VENDOR_REQUEST_WRITE_REGISTER, int32]]
USB_VENDOR_REQUEST_GET_STATS ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_GET_STATS, array[int8, 47]]]
} [packed]
define LAN78XX_REG_TYPE_IN (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
define LAN78XX_REG_TYPE_OUT (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
]
|
| 87/2 |
2026/07/30 12:23 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 139351
output: 27
thoughts: 2251
Thoughts: **USB Device Descriptors and the au0828 Driver**
Okay, so I'm thinking about how to trigger the `au0828` driver via `syz_usb_connect`. My initial thought is to just use `syz_usb_connect` directly with the vendor and product IDs `0x2040` and `0x7200`. I know `syz_usb_connect` takes a `usb_device_descriptor`, which should be fine. I'll just pass the `usb_device_descriptor_t` and set the vendor/product IDs.
I immediately need to remember that the `au0828` driver is a *media* driver, so there will likely be endpoints involved. Checking the `au0828_usb_probe` function I see endpoint access, so I know I'll need to account for that. Specifically, it accesses `endpoint[isoc_pipe]` and there's a check for `bNumEndpoints`. So, if there are no endpoints, things will crash. I confirm that it requires at least one endpoint.
The next thought is to just craft a generic descriptor, patch the IDs in the syzkaller program, but a quick check reveals that `syzkaller` *does* allow patching of `idVendor` and `idProduct` using Go code. The note clarifies that these, along with `bDeviceClass`, `bDeviceSubClass`, `bDeviceProtocol`, and `bcdDevice` are patched by Go code. Wait, I realize I can just write the raw bytes directly. I need to use `&AUTO="..."` or `&AUTO={...}`.
I now decide to build a complete valid USB descriptor for the `au0828`. I need a device, configuration, interface, and endpoint descriptors. I start by constructing the device descriptor (18 bytes), then the config descriptor (9 bytes), which includes an interface association descriptor (IAD, 8 bytes). The IAD will have `bFirstInterface = 1` which is relevant to the probe. Then a dummy interface 0, an interface 1 (which is the actual `au0828`), and finally an endpoint descriptor. It's clear that the total length in the config descriptor needs to accommodate all the descriptors. I need to recalculate `wTotalLength`. I remember to include the IAD and dummy interface 0. I now recalculate it, and construct it again.
Okay, I've got my hex string and I am ready to try it. Wait, the `au0828_usb_probe` function seems to expect an Interface Association Descriptor (IAD) and the code checks `assoc_desc->bFirstInterface` against `ifnum`, which is 1. My IAD is good because it has `bFirstInterface = 1`.
Now I'm looking at `au0828_usb_probe` and I'm seeing an access to `udev->actconfig->interface[idx]`, but what is `idx` and `dev->current_pcb_config`? Oh, wait, I'm thinking of the `cx231xx` probe, not `au0828`. Let's just focus on the `au0828` probe.
|
| 88/2 |
2026/07/30 12:23 |
tool |
codesearch-definition-source |
0m
Args: map[Name:au0828_usb_probe]
Results: map[SourceCode: 643: static int au0828_usb_probe(struct usb_interface *interface,
644: const struct usb_device_id *id)
645: {
646: int ifnum;
647: int retval = 0;
648:
649: struct au0828_dev *dev;
650: struct usb_device *usbdev = interface_to_usbdev(interface);
651:
652: ifnum = interface->altsetting->desc.bInterfaceNumber;
653:
654: if (ifnum != 0)
655: return -ENODEV;
656:
657: dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
658: le16_to_cpu(usbdev->descriptor.idVendor),
659: le16_to_cpu(usbdev->descriptor.idProduct),
660: ifnum);
661:
662: /*
663: * Make sure we have 480 Mbps of bandwidth, otherwise things like
664: * video stream wouldn't likely work, since 12 Mbps is generally
665: * not enough even for most Digital TV streams.
666: */
667: if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
668: pr_err("au0828: Device initialization failed.\n");
669: pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
670: return -ENODEV;
671: }
672:
673: dev = kzalloc_obj(*dev);
674: if (dev == NULL) {
675: pr_err("%s() Unable to allocate memory\n", __func__);
676: return -ENOMEM;
677: }
678:
679: mutex_init(&dev->lock);
680: mutex_lock(&dev->lock);
681: mutex_init(&dev->mutex);
682: mutex_init(&dev->dvb.lock);
683: dev->usbdev = usbdev;
684: dev->boardnr = id->driver_info;
685: dev->board = au0828_boards[dev->boardnr];
686:
687: /* Initialize the media controller */
688: retval = au0828_media_device_init(dev, usbdev);
689: if (retval) {
690: pr_err("%s() au0828_media_device_init failed\n",
691: __func__);
692: mutex_unlock(&dev->lock);
693: kfree(dev);
694: return retval;
695: }
696:
697: retval = au0828_v4l2_device_register(interface, dev);
698: if (retval) {
699: au0828_usb_v4l2_media_release(dev);
700: mutex_unlock(&dev->lock);
701: kfree(dev);
702: return retval;
703: }
704:
705: /* Power Up the bridge */
706: au0828_write(dev, REG_600, 1 << 4);
707:
708: /* Bring up the GPIO's and supporting devices */
709: au0828_gpio_setup(dev);
710:
711: /* I2C */
712: au0828_i2c_register(dev);
713:
714: /* Setup */
715: au0828_card_setup(dev);
716:
717: /*
718: * Store the pointer to the au0828_dev so it can be accessed in
719: * au0828_usb_disconnect
720: */
721: usb_set_intfdata(interface, dev);
722:
723: /* Analog TV */
724: retval = au0828_analog_register(dev, interface);
725: if (retval) {
726: pr_err("%s() au0828_analog_register failed to register on V4L2\n",
727: __func__);
728: mutex_unlock(&dev->lock);
729: goto done;
730: }
731:
732: /* Digital TV */
733: retval = au0828_dvb_register(dev);
734: if (retval)
735: pr_err("%s() au0828_dvb_register failed\n",
736: __func__);
737:
738: /* Remote controller */
739: au0828_rc_register(dev);
740:
741: pr_info("Registered device AU0828 [%s]\n",
742: dev->board.name == NULL ? "Unset" : dev->board.name);
743:
744: mutex_unlock(&dev->lock);
745:
746: retval = au0828_media_device_register(dev, usbdev);
747:
748: done:
749: if (retval < 0)
750: au0828_usb_disconnect(interface);
751:
752: return retval;
753: }
SourceFile:drivers/media/usb/au0828/au0828-core.c]
|
| 89/2 |
2026/07/30 12:23 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 144037
output: 25
thoughts: 3477
Thoughts: **Analyzing the USB Probe and I2C Adapter Bug**
Okay, so the initial plan hinges on getting `au0828_usb_probe` to trigger. I've realized that it expects a specific USB configuration: a single interface (0) and high speed. With this knowledge, I've constructed the necessary USB descriptors (device, config, interface, and endpoint) in hex format, which will be passed to `syz_usb_connect`. The connection will be at `USB_SPEED_HIGH`, or 3, according to the `vusb.txt` documentation.
Now I'm looking at `syz_usb_connect`. It seems like I need to supply some `conn_descs`. Although `conn_descs` appears to be optional, it is defined as a pointer, which means it could crash if null, so I'll pass a zeroed-out `&AUTO` structure for it.
The next issue is keeping the `au0828_dev` alive. I'm going to attempt to reproduce the bug by opening some `/dev/videoX` and `/dev/i2c-X` devices. It's likely that a dynamic I2C adapter assignment will be needed, so I'll open several. I'll need to call `ioctl(fd, I2C_SMBUS, ...)` on the opened I2C devices to interact with the USB device.
I've crafted a syzkaller program that first connects a USB device using the previously constructed descriptors and a high speed setting. Then, it opens and holds open a few video and I2C devices. Finally, it disconnects the USB device and attempts the `I2C_SMBUS` ioctl calls.
After reviewing the code again, I've ensured that the `I2C_SMBUS` command code is 0x720. I've also made sure I understand the `i2c_smbus_ioctl_data` structure and will pass the appropriate arguments to it with the syzkaller calls.
However, I've had a thought that the target driver, `au0828`, may not be the culprit, so I've been considering other candidates. I've been analyzing the KASAN report and matching the allocation sizes in the report with USB driver data structures, specifically the `i2c_adapter` and its link to the `usb_device` structure. I've deduced that the error may not be in the `dvb_usb` or `dvb_usb_v2`, nor `hdpvr`, drivers because of how they handle the I2C adapter removal. It seems, based on the allocation sizes in the KASAN report, that `pvrusb2` is the likely cause. It would appear that the disconnecting of the USB device may free the underlying `usb_device` structure while the I2C adapter is still registered. I'll need to double check the USB IDs used by `pvrusb2`.
|
| 90/2 |
2026/07/30 12:23 |
tool |
codesearch-definition-source |
0m
Args: map[Name:pvr2_device_table]
Results: map[SourceCode: 684: struct usb_device_id pvr2_device_table[] = {
685: { USB_DEVICE(0x2040, 0x2900),
686: .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
687: { USB_DEVICE(0x2040, 0x2950), /* Logically identical to 2900 */
688: .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
689: { USB_DEVICE(0x2040, 0x2400),
690: .driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
691: { USB_DEVICE(0x1164, 0x0622),
692: .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
693: { USB_DEVICE(0x1164, 0x0602),
694: .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d},
695: { USB_DEVICE(0x11ba, 0x1003),
696: .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
697: { USB_DEVICE(0x11ba, 0x1001),
698: .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
699: { USB_DEVICE(0x2040, 0x7300),
700: .driver_info = (kernel_ulong_t)&pvr2_device_73xxx},
701: { USB_DEVICE(0x2040, 0x7500),
702: .driver_info = (kernel_ulong_t)&pvr2_device_750xx},
703: { USB_DEVICE(0x2040, 0x7501),
704: .driver_info = (kernel_ulong_t)&pvr2_device_751xx},
705: { USB_DEVICE(0x0ccd, 0x0039),
706: .driver_info = (kernel_ulong_t)&pvr2_device_av400},
707: { USB_DEVICE(0x2040, 0x7502),
708: .driver_info = (kernel_ulong_t)&pvr2_device_160111},
709: { USB_DEVICE(0x2040, 0x7510),
710: .driver_info = (kernel_ulong_t)&pvr2_device_160000},
711: { }
712: };
SourceFile:drivers/media/usb/pvrusb2/pvrusb2-devattr.c]
|
| 91/2 |
2026/07/30 12:23 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 149027
output: 23
thoughts: 84
Thoughts: Here's my thought process, as it stands:
**Device Identification and Requirements**
Okay, so I'm cross-referencing some device IDs against known drivers. I've got `0x2040, 0x2900` β that's definitely `pvrusb2`. And then there's `0x2040, 0x7200` β ah, that's `au0828`. Not surprising, I see those quite a bit.
Now I'm diving deeper into the nuances... Right, the `au0828` driver. I recall now that this chipset *demands* a high-speed USB connection, represented by `USB_SPEED_HIGH`, and that it always seems to like being on interface number 0, indicated by `ifnum == 0`. It's finicky, that one.
But what about `pvrusb2`? I know *what* it is, but what are its specific USB requirements? I need to quickly recall what it needs in terms of USB speed and interface assignments to make sure things are configured correctly. I need to refresh that in my head.
|
| 92/2 |
2026/07/30 12:24 |
tool |
codesearch-definition-source |
0m
Error:
Args:
Results: map[SourceCode: SourceFile:]
|
| 93/2 |
2026/07/30 12:24 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 149408
output: 35
thoughts: 13
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Diving into the `pvrusb2` Probe Function**
Okay, time to get my hands dirty. Let's start with the `pvrusb2` probe function. I need to refresh my memory on the initialization sequence and resource allocation, particularly around the interaction with the USB subsystem. What are the key points of the device matching and the driver registration within this function? I want to trace the hardware identification process and understand how it negotiates the interface settings, endpoint configuration and how it interacts with the firmware loading process (if applicable). I also need to make a note of potential race conditions or locking issues within the function. I should also check the error handling and debugging outputs of the probe, as it will be useful during bring-up. Where is it handling any specific vendor or device IDs? That's always a good place to begin.
|
| 94/2 |
2026/07/30 12:24 |
tool |
grepper |
0m
Args: map[Expression:\.probe.*= PathPrefix:drivers/media/usb/pvrusb2/]
Results: map[Output:drivers/media/usb/pvrusb2/pvrusb2-devattr.c=310=static struct tda829x_config tda829x_no_probe = {
drivers/media/usb/pvrusb2/pvrusb2-devattr.c:311: .probe_tuner = TDA829X_DONT_PROBE,
drivers/media/usb/pvrusb2/pvrusb2-devattr.c-312-};
--
drivers/media/usb/pvrusb2/pvrusb2-main.c=85=static struct usb_driver pvr_driver = {
--
drivers/media/usb/pvrusb2/pvrusb2-main.c-87- .id_table = pvr2_device_table,
drivers/media/usb/pvrusb2/pvrusb2-main.c:88: .probe = pvr_probe,
drivers/media/usb/pvrusb2/pvrusb2-main.c-89- .disconnect = pvr_disconnect
]
|
| 95/2 |
2026/07/30 12:24 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 149927
output: 22
thoughts: 10
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**Initial Diagnostic Step**
Right, let's start with a sanity check. Before diving too deep, I'll begin by verifying the primary sensor's behavior. I need to examine the function of `pvr_probe`. It's the go-to first step for most of these issues, so I'll see if it's returning anything immediately, or throwing errors. This is usually where I can tell, within a few seconds, if the problem is fundamental or not. I'm going to look at the logs and make a determination.
|
| 96/2 |
2026/07/30 12:24 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 48: static int pvr_probe(struct usb_interface *intf,
49: const struct usb_device_id *devid)
50: {
51: struct pvr2_context *pvr;
52:
53: /* Create underlying hardware interface */
54: pvr = pvr2_context_create(intf,devid,pvr_setup_attach);
55: if (!pvr) {
56: pvr2_trace(PVR2_TRACE_ERROR_LEGS,
57: "Failed to create hdw handler");
58: return -ENOMEM;
59: }
60:
61: pvr2_trace(PVR2_TRACE_INIT,"pvr_probe(pvr=%p)",pvr);
62:
63: usb_set_intfdata(intf, pvr);
64:
65: return 0;
66: }
SourceFile:drivers/media/usb/pvrusb2/pvrusb2-main.c]
|
| 97/2 |
2026/07/30 12:24 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 150409
output: 25
thoughts: 45
Thoughts: Okay, here's my interpretation of those thoughts, framed as my own:
**Analyzing the `pvrusb2` Driver's Probing Mechanism**
Right, let me see... I'm looking at this `pvrusb2` driver and its probing routine. It seems like it's taking a more straightforward approach compared to some others I've seen. Specifically, it doesn't appear to explicitly validate the `ifnum` or `speed` parameters directly within the `pvr_probe` function. That's interesting; it's definitely a simpler approach at this initial stage. I wonder if this simplification has advantages, or potential downsides, down the road.
Hang on a minute⦠it just clicked! My gut tells me that `pvr2_context_create` is the function that likely handles those specific checks of interface number and device speed. Let me double check, I might have the function name wrong... yes, that's it. It would make sense to defer those validations until the context is actually being created. Okay, that makes more sense.
|
| 98/2 |
2026/07/30 12:24 |
tool |
codesearch-definition-source |
0m
Args: map[Name:pvr2_context_create]
Results: map[SourceCode: 201: struct pvr2_context *pvr2_context_create(
202: struct usb_interface *intf,
203: const struct usb_device_id *devid,
204: void (*setup_func)(struct pvr2_context *))
205: {
206: struct pvr2_context *mp = NULL;
207: mp = kzalloc_obj(*mp);
208: if (!mp) goto done;
209: pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
210: mp->setup_func = setup_func;
211: mutex_init(&mp->mutex);
212: mutex_lock(&pvr2_context_mutex);
213: mp->exist_prev = pvr2_context_exist_last;
214: mp->exist_next = NULL;
215: pvr2_context_exist_last = mp;
216: if (mp->exist_prev) {
217: mp->exist_prev->exist_next = mp;
218: } else {
219: pvr2_context_exist_first = mp;
220: }
221: mutex_unlock(&pvr2_context_mutex);
222: mp->hdw = pvr2_hdw_create(intf,devid);
223: if (!mp->hdw) {
224: pvr2_context_destroy(mp);
225: mp = NULL;
226: goto done;
227: }
228: pvr2_context_set_notify(mp, !0);
229: done:
230: return mp;
231: }
SourceFile:drivers/media/usb/pvrusb2/pvrusb2-context.c]
|
| 99/2 |
2026/07/30 12:24 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 151249
output: 26
thoughts: 15
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Hardware Context Creation - `pvr2_hdw_create`**
Right, let's break this down. `pvr2_hdw_create`. Straight away, I'm thinking about the low-level hardware context. It's the foundation, the scaffolding, the root from which everything else in the graphics pipeline will grow. This function, `pvr2_hdw_create`, is absolutely critical. It's the point where we instantiate the hardware resources needed for our rendering operations.
I'm imagining all the underlying setup: allocating memory, initializing registers, ensuring proper communication channels, and configuring whatever PVR-specific hardware is involved. Is it a unified memory architecture? Discrete? What clock rates are we dealing with? Is there a need for cache configuration or memory aliasing? Depending on the architecture it could be allocating command buffers, setting up DMA channels, or enabling interrupt vectors.
There are many design considerations to think about. What error handling is in place? What access controls are there to ensure safe operation? `pvr2_hdw_create` would need to be robust β you can't have a flaky foundation. You've got to ensure the structure, the drivers, the devices, can work together. This is where it all begins. And without a properly functioning hardware context, nothing else will work. So, this function's got to be bulletproof.
|
| 100/2 |
2026/07/30 12:24 |
tool |
codesearch-definition-source |
0m
Args: map[Name:pvr2_hdw_create]
Results: map[SourceCode:2344: /* Create, set up, and return a structure for interacting with the
2345: underlying hardware. */
2346: struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
2347: const struct usb_device_id *devid)
2348: {
2349: unsigned int idx,cnt1,cnt2,m;
2350: struct pvr2_hdw *hdw = NULL;
2351: int valid_std_mask;
2352: struct pvr2_ctrl *cptr;
2353: struct usb_device *usb_dev;
2354: const struct pvr2_device_desc *hdw_desc;
2355: __u8 ifnum;
2356: struct v4l2_queryctrl qctrl;
2357: struct pvr2_ctl_info *ciptr;
2358:
2359: usb_dev = interface_to_usbdev(intf);
2360:
2361: hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
2362:
2363: if (hdw_desc == NULL) {
2364: pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create: No device description pointer, unable to continue.");
2365: pvr2_trace(PVR2_TRACE_INIT,
2366: "If you have a new device type, please contact Mike Isely <isely@pobox.com> to get it included in the driver");
2367: goto fail;
2368: }
2369:
2370: hdw = kzalloc_obj(*hdw);
2371: pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
2372: hdw,hdw_desc->description);
2373: pvr2_trace(PVR2_TRACE_INFO, "Hardware description: %s",
2374: hdw_desc->description);
2375: if (hdw_desc->flag_is_experimental) {
2376: pvr2_trace(PVR2_TRACE_INFO, "**********");
2377: pvr2_trace(PVR2_TRACE_INFO,
2378: "***WARNING*** Support for this device (%s) is experimental.",
2379: hdw_desc->description);
2380: pvr2_trace(PVR2_TRACE_INFO,
2381: "Important functionality might not be entirely working.");
2382: pvr2_trace(PVR2_TRACE_INFO,
2383: "Please consider contacting the driver author to help with further stabilization of the driver.");
2384: pvr2_trace(PVR2_TRACE_INFO, "**********");
2385: }
2386: if (!hdw) goto fail;
2387:
2388: timer_setup(&hdw->quiescent_timer, pvr2_hdw_quiescent_timeout, 0);
2389:
2390: timer_setup(&hdw->decoder_stabilization_timer,
2391: pvr2_hdw_decoder_stabilization_timeout, 0);
2392:
2393: timer_setup(&hdw->encoder_wait_timer, pvr2_hdw_encoder_wait_timeout,
2394: 0);
2395:
2396: timer_setup(&hdw->encoder_run_timer, pvr2_hdw_encoder_run_timeout, 0);
2397:
2398: hdw->master_state = PVR2_STATE_DEAD;
2399:
2400: init_waitqueue_head(&hdw->state_wait_data);
2401:
2402: hdw->tuner_signal_stale = !0;
2403: cx2341x_fill_defaults(&hdw->enc_ctl_state);
2404:
2405: /* Calculate which inputs are OK */
2406: m = 0;
2407: if (hdw_desc->flag_has_analogtuner) m |= 1 << PVR2_CVAL_INPUT_TV;
2408: if (hdw_desc->digital_control_scheme != PVR2_DIGITAL_SCHEME_NONE) {
2409: m |= 1 << PVR2_CVAL_INPUT_DTV;
2410: }
2411: if (hdw_desc->flag_has_svideo) m |= 1 << PVR2_CVAL_INPUT_SVIDEO;
2412: if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE;
2413: if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO;
2414: hdw->input_avail_mask = m;
2415: hdw->input_allowed_mask = hdw->input_avail_mask;
2416:
2417: /* If not a hybrid device, pathway_state never changes. So
2418: initialize it here to what it should forever be. */
2419: if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_DTV))) {
2420: hdw->pathway_state = PVR2_PATHWAY_ANALOG;
2421: } else if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_TV))) {
2422: hdw->pathway_state = PVR2_PATHWAY_DIGITAL;
2423: }
2424:
2425: hdw->control_cnt = CTRLDEF_COUNT;
2426: hdw->control_cnt += MPEGDEF_COUNT;
2427: hdw->controls = kzalloc_objs(struct pvr2_ctrl, hdw->control_cnt);
2428: if (!hdw->controls) goto fail;
2429: hdw->hdw_desc = hdw_desc;
2430: hdw->ir_scheme_active = hdw->hdw_desc->ir_scheme;
2431: for (idx = 0; idx < hdw->control_cnt; idx++) {
2432: cptr = hdw->controls + idx;
2433: cptr->hdw = hdw;
2434: }
2435: for (idx = 0; idx < 32; idx++) {
2436: hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx];
2437: }
2438: for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
2439: cptr = hdw->controls + idx;
2440: cptr->info = control_defs+idx;
2441: }
2442:
2443: /* Ensure that default input choice is a valid one. */
2444: m = hdw->input_avail_mask;
2445: if (m) for (idx = 0; idx < (sizeof(m) << 3); idx++) {
2446: if (!((1UL << idx) & m)) continue;
2447: hdw->input_val = idx;
2448: break;
2449: }
2450:
2451: /* Define and configure additional controls from cx2341x module. */
2452: hdw->mpeg_ctrl_info = kzalloc_objs(*(hdw->mpeg_ctrl_info),
2453: MPEGDEF_COUNT);
2454: if (!hdw->mpeg_ctrl_info) goto fail;
2455: for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
2456: cptr = hdw->controls + idx + CTRLDEF_COUNT;
2457: ciptr = &(hdw->mpeg_ctrl_info[idx].info);
2458: ciptr->desc = hdw->mpeg_ctrl_info[idx].desc;
2459: ciptr->name = mpeg_ids[idx].strid;
2460: ciptr->v4l_id = mpeg_ids[idx].id;
2461: ciptr->skip_init = !0;
2462: ciptr->get_value = ctrl_cx2341x_get;
2463: ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags;
2464: ciptr->is_dirty = ctrl_cx2341x_is_dirty;
2465: if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty;
2466: qctrl.id = ciptr->v4l_id;
2467: cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl);
2468: if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) {
2469: ciptr->set_value = ctrl_cx2341x_set;
2470: }
2471: strscpy(hdw->mpeg_ctrl_info[idx].desc, qctrl.name,
2472: sizeof(hdw->mpeg_ctrl_info[idx].desc));
2473: ciptr->default_value = qctrl.default_value;
2474: switch (qctrl.type) {
2475: default:
2476: case V4L2_CTRL_TYPE_INTEGER:
2477: ciptr->type = pvr2_ctl_int;
2478: ciptr->def.type_int.min_value = qctrl.minimum;
2479: ciptr->def.type_int.max_value = qctrl.maximum;
2480: break;
2481: case V4L2_CTRL_TYPE_BOOLEAN:
2482: ciptr->type = pvr2_ctl_bool;
2483: break;
2484: case V4L2_CTRL_TYPE_MENU:
2485: ciptr->type = pvr2_ctl_enum;
2486: ciptr->def.type_enum.value_names =
2487: cx2341x_ctrl_get_menu(&hdw->enc_ctl_state,
2488: ciptr->v4l_id);
2489: for (cnt1 = 0;
2490: ciptr->def.type_enum.value_names[cnt1] != NULL;
2491: cnt1++) { }
2492: ciptr->def.type_enum.count = cnt1;
2493: break;
2494: }
2495: cptr->info = ciptr;
2496: }
2497:
2498: // Initialize control data regarding video standard masks
2499: valid_std_mask = pvr2_std_get_usable();
2500: for (idx = 0; idx < 32; idx++) {
2501: if (!(valid_std_mask & (1UL << idx))) continue;
2502: cnt1 = pvr2_std_id_to_str(
2503: hdw->std_mask_names[idx],
2504: sizeof(hdw->std_mask_names[idx])-1,
2505: 1UL << idx);
2506: hdw->std_mask_names[idx][cnt1] = 0;
2507: }
2508: cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL);
2509: if (cptr) {
2510: memcpy(&hdw->std_info_avail,cptr->info,
2511: sizeof(hdw->std_info_avail));
2512: cptr->info = &hdw->std_info_avail;
2513: hdw->std_info_avail.def.type_bitmask.bit_names =
2514: hdw->std_mask_ptrs;
2515: hdw->std_info_avail.def.type_bitmask.valid_bits =
2516: valid_std_mask;
2517: }
2518: cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR);
2519: if (cptr) {
2520: memcpy(&hdw->std_info_cur,cptr->info,
2521: sizeof(hdw->std_info_cur));
2522: cptr->info = &hdw->std_info_cur;
2523: hdw->std_info_cur.def.type_bitmask.bit_names =
2524: hdw->std_mask_ptrs;
2525: hdw->std_info_cur.def.type_bitmask.valid_bits =
2526: valid_std_mask;
2527: }
2528: cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDDETECT);
2529: if (cptr) {
2530: memcpy(&hdw->std_info_detect,cptr->info,
2531: sizeof(hdw->std_info_detect));
2532: cptr->info = &hdw->std_info_detect;
2533: hdw->std_info_detect.def.type_bitmask.bit_names =
2534: hdw->std_mask_ptrs;
2535: hdw->std_info_detect.def.type_bitmask.valid_bits =
2536: valid_std_mask;
2537: }
2538:
2539: hdw->cropcap_stale = !0;
2540: hdw->eeprom_addr = -1;
2541: hdw->unit_number = -1;
2542: hdw->v4l_minor_number_video = -1;
2543: hdw->v4l_minor_number_vbi = -1;
2544: hdw->v4l_minor_number_radio = -1;
2545: hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
2546: if (!hdw->ctl_write_buffer) goto fail;
2547: hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
2548: if (!hdw->ctl_read_buffer) goto fail;
2549: hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL);
2550: if (!hdw->ctl_write_urb) goto fail;
2551: hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
2552: if (!hdw->ctl_read_urb) goto fail;
2553:
2554: if (v4l2_device_register(&intf->dev, &hdw->v4l2_dev) != 0) {
2555: pvr2_trace(PVR2_TRACE_ERROR_LEGS,
2556: "Error registering with v4l core, giving up");
2557: goto fail;
2558: }
2559: mutex_lock(&pvr2_unit_mtx);
2560: do {
2561: for (idx = 0; idx < PVR_NUM; idx++) {
2562: if (unit_pointers[idx]) continue;
2563: hdw->unit_number = idx;
2564: unit_pointers[idx] = hdw;
2565: break;
2566: }
2567: } while (0);
2568: mutex_unlock(&pvr2_unit_mtx);
2569:
2570: INIT_WORK(&hdw->workpoll, pvr2_hdw_worker_poll);
2571:
2572: if (hdw->unit_number == -1)
2573: goto fail;
2574:
2575: cnt1 = 0;
2576: cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2");
2577: cnt1 += cnt2;
2578: if (hdw->unit_number >= 0) {
2579: cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c",
2580: ('a' + hdw->unit_number));
2581: cnt1 += cnt2;
2582: }
2583: if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
2584: hdw->name[cnt1] = 0;
2585:
2586: pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
2587: hdw->unit_number,hdw->name);
2588:
2589: hdw->tuner_type = -1;
2590: hdw->flag_ok = !0;
2591:
2592: hdw->usb_intf = intf;
2593: hdw->usb_dev = usb_dev;
2594:
2595: usb_make_path(hdw->usb_dev, hdw->bus_info, sizeof(hdw->bus_info));
2596:
2597: ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
2598: usb_set_interface(hdw->usb_dev,ifnum,0);
2599:
2600: mutex_init(&hdw->ctl_lock_mutex);
2601: mutex_init(&hdw->big_lock_mutex);
2602:
2603: return hdw;
2604: fail:
2605: if (hdw) {
2606: timer_shutdown_sync(&hdw->quiescent_timer);
2607: timer_shutdown_sync(&hdw->decoder_stabilization_timer);
2608: timer_shutdown_sync(&hdw->encoder_run_timer);
2609: timer_shutdown_sync(&hdw->encoder_wait_timer);
2610: flush_work(&hdw->workpoll);
2611: v4l2_device_unregister(&hdw->v4l2_dev);
2612: usb_free_urb(hdw->ctl_read_urb);
2613: usb_free_urb(hdw->ctl_write_urb);
2614: kfree(hdw->ctl_read_buffer);
2615: kfree(hdw->ctl_write_buffer);
2616: kfree(hdw->controls);
2617: kfree(hdw->mpeg_ctrl_info);
2618: kfree(hdw);
2619: }
2620: return NULL;
2621: }
SourceFile:drivers/media/usb/pvrusb2/pvrusb2-hdw.c]
|
| 101/2 |
2026/07/30 12:24 |
llm |
crash-repro-finder |
2m
Model:
Tokens:
input: 156964
output: 1361
thoughts: 10608
Thoughts: **Reproducer Refinement for I2C Race Condition**
Okay, so here's the game plan, based on everything I've seen so far. The initial idea of exploiting `pvrusb2` is simpler, but that one is asynchronous and I'm still trying to figure it out. `au0828` looks much more promising because it's synchronous during device registration. I'm going with it for now. The device descriptor I have should work fine.
First, the key is to trigger a race condition between the device unregistration on USB disconnect and an I2C operation. I've got a way to make it more likely. The `au0828` driver registers the I2C adapter *before* the video device. So if I can successfully open a `/dev/videoX` device, I know the I2C adapter has been registered. That's my "synchronization" signal β opening a video device means the I2C part is ready.
The core steps are:
1. **Connect the USB device:** `syz_usb_connect`. I'm using the `au0828` descriptors. This one is synchronous, but the probe might execute in a workqueue later, but not before the devices are registered.
2. **Open video and I2C devices concurrently:** I'll *immediately* start opening `/dev/video0` through `/dev/video3` and `/dev/i2c-0` through `/dev/i2c-3`, then `/dev/i2c-4` to `/dev/i2c-7` a few times to get more coverage. I'll open all the video and I2C devices to maximize the probability of success.
3. **Disconnect USB:** `syz_usb_disconnect`. This should trigger unregistration and thus cause the race condition.
4. **Execute the `I2C_SMBUS` ioctl:** Run `ioctl(I2C_SMBUS)` on each of the I2C devices I opened. If the disconnect happened at the right time, this should hit the vulnerability.
To improve reliability, I'm repeating the `openat` calls. It gives the kernel more time to register the I2C device before the disconnect. Also, even if an `openat` call fails, the next one may succeed if the driver managed to register the device. The multiple attempts will improve the probability of hitting the race.
The reproducer looks like this:
```
r0 = syz_usb_connect(3, 0x2b, &AUTO="\x12\x01\x00\x02\x00\x00\x00\x40\x40\x20\x00\x72\x00\x00\x01\x02\x03\x01\x09\x02\x19\x00\x01\x01\x00\x80\xfa\x09\x04\x00\x00\x01\xff\x00\x00\x00\x07\x05\x81\x02\x00\x02\x00", 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r7 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r8 = openat$video1(0xffffff
|
| 102/2 |
2026/07/30 12:27 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0x2b, &AUTO="\x12\x01\x00\x02\x00\x00\x00\x40\x40\x20\x00\x72\x00\x00\x01\x02\x03\x01\x09\x02\x19\x00\x01\x01\x00\x80\xfa\x09\x04\x00\x00\x01\xff\x00\x00\x00\x07\x05\x81\x02\x00\x02\x00", 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r7 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r8 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r9 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r10 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r11 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r12 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r13 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r14 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r15 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r16 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r17 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r18 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r9, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r10, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r11, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r12, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r15, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r16, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r17, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r18, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 103/2 |
2026/07/30 12:27 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 170182
output: 1277
thoughts: 273
Thoughts: **My Thought Process on the `&AUTO` Syntax**
Okay, it seems I've stumbled upon an invalid syntax attempt with `&AUTO="..."`. That won't fly. I'm pretty sure it needs to be `&AUTO='\x12\x01...'` (using single quotes for raw bytes) or potentially `&AUTO="1201..."` (using double quotes for a hex string). Let's double-check the documentation, always the best approach.
Ah, here it is: `string-arg = "'" escaped-string "'" | "\"" escaped-string "\"" | "\"$" escaped-string "\""`. Okay, the syntax clearly outlines the acceptable string arguments. Now, am I right in thinking that `&AUTO="01010101"` is indeed a hex string? Time to verify...
Yep, let's look at a concrete example. The documentation gives: `# Perform a write operation` `write(r0, &AUTO="01010101", 0x4)`. That seals it; double quotes *do* mean hex strings! Excellent.
Right, so I'll try the hex string approach with double quotes. I'm going to feed the code: `&AUTO="1201000200000040402000720000010203010902190001010080fa0904000001ff00000007058102000200"`.
Wait, just a sanity check: I need to verify the length of the hex string β it *should* correspond to the intended byte size. Length check... Yup, it's 43 bytes = 0x2b, which I was hoping for. Now, I'll attempt to run this code.
|
| 104/2 |
2026/07/30 12:27 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0x2b, &AUTO="1201000200000040402000720000010203010902190001010080fa0904000001ff00000007058102000200", 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r7 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r8 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r9 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r10 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r11 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r12 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r13 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r14 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r15 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r16 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r17 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r18 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r9, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r10, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r11, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r12, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r15, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r16, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r17, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r18, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 105/2 |
2026/07/30 12:27 |
llm |
crash-repro-finder-compressor |
0m
Model:
Reply: ### 1. Approaches Tried and Results
* **KASAN Report Analysis**:
* Analyzed the slab-use-after-free read of size 8 at offset 264 (`0x108`) inside a `kmalloc-4k` object.
* The allocation/free stack traces in the report point to `skb->head` allocated/freed by `netdevsim` (`nsim_dev_trap_skb_build`). This is a reallocation noise/red herring; the original object was a `struct usb_device` (size ~2251 bytes, fits in `kmalloc-4k`).
* Mapped the offsets: `usb_device->dev` is at offset 176 (`0xb0`). The crash occurs in `i2c_adapter_depth` at `if (parent->type == &i2c_adapter_type)`. `parent` is `adapter->dev.parent` which points to `&usb_device->dev` (offset 176). `parent->type` is at offset 88 inside `struct device`, making the final offset `176 + 88 = 264` (`0x108`), perfectly matching the KASAN report.
* **Driver Code Auditing**:
* Searched for USB drivers setting `adapter->dev.parent = &usb_device->dev` and deferring `i2c_del_adapter` on disconnect.
* `cx231xx` was ruled out because it sets `parent` to `usb_interface` (allocated in `kmalloc-2k`).
* `dvb_usb` and `dvb_usb_v2` were ruled out because they free their private context `d` (which embeds `i2c_adapter`) directly in `disconnect`, which would trigger a UAF on `dvb_usb_device` (`kmalloc-16k`) instead of `usb_device`.
* `au0828` and `pvrusb2` are highly viable candidates. Both set `adapter->dev.parent = &usb_device->dev` and defer the unregistration of the I2C adapter (via `i2c_del_adapter`) to a release callback that is only triggered when all V4L2 users (e.g., `/dev/videoX`) close their file descriptors.
### 2. Current Hypotheses
* **Deferred Cleanup Race**:
1. A USB media device (e.g., `au0828` or `pvrusb2`) is connected.
2. User space opens `/dev/video0` (incrementing the driver's private context refcount) and `/dev/i2c-0` (incrementing the I2C adapter's refcount).
3. The USB device is disconnected.
4. The driver's `disconnect` callback runs. Because `/dev/video0` is open, the driver defers resource release (including `i2c_del_adapter`) and returns.
5. The USB core proceeds to delete the interface and eventually frees the `struct usb_device`.
6. The I2C adapter remains registered because `i2c_del_adapter` was never called. Its `dev.parent` still points to the now-freed `usb_device`.
7. User space calls `ioctl(fd_i2c, I2C_SMBUS, ...)` on `/dev/i2c-0`. This triggers `i2c_adapter_depth` which dereferences `adapter->dev.parent->type`, causing the UAF.
### 3. Critical Code and Configuration Values
* **Dangling Parent Pointer Dereference**:
```c
// drivers/i2c/i2c-core-base.c
unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
{
unsigned int depth = 0;
struct device *parent;
for (parent = adapter->dev.parent; parent; parent = parent->parent)
if (parent->type == &i2c_adapter_type) // UAF here: parent points to freed usb_device
depth++;
...
}
```
* **Deferred Release in `au0828`**:
```c
// drivers/media/usb/au0828/au0828-core.c
static void au0828_usb_disconnect(struct usb_interface *interface)
{
...
if (au0828_analog_unregister(dev)) {
return; // Returns early if V4L2 is open, deferring au0828_usb_release
}
au0828_usb_release(dev);
}
void au0828_usb_release(struct au0828_dev *dev)
{
...
au0828_i2c_unregister(dev); // Calls i2c_del_adapter
kfree(dev);
}
```
* **USB IDs**:
* `au0828`: Vendor `0x2040`, Product `0x7200`
* `pvrusb2`: Vendor `0x2040`, Product `0x2900`
### 4. Syzkaller Program Structure (Draft)
```syzlang
# Connect au0828 USB device (High Speed, Interface 0)
r0 = syz_usb_connect(3, 0x2b, &AUTO="\x12\x01\x00\x02\x00\x00\x00\x40\x40\x20\x00\x72\x00\x00\x01\x02\x03\x01\x09\x02\x19\x00\x01\x01\x00\x80\xfa\x09\x04\x00\x00\x01\xff\x00\x00\x00\x07\x05\x81\x02\x00\x02\x00", 0)
# Open video device to hold driver context
r1 = openat(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
# Open I2C device
r2 = openat(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
# Disconnect USB device to trigger deferred disconnect
syz_usb_disconnect(r0)
# Trigger I2C transaction to execute i2c_adapter_depth
ioctl$I2C_SMBUS(r2, 0x720, &AUTO={0, 0, 0, 0})
```
Tokens:
input: 171501
output: 1616
thoughts: 1802
|
| 106/2 |
2026/07/30 12:28 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 35773
output: 1361
thoughts: 768
Thoughts: **Debugging USB Connection Descriptors**
Okay, wait a minute, I think I messed up that `&AUTO="1201..."` value. That doesn't seem right. Right, let me check `syz_usb_connect` again. Ah, right, it takes `conn_descs`, which is a pointer to a `vusb_connect_descriptors` struct. Okay, so it looks like it is expecting the following structure.
```c
vusb_connect_descriptors {
qual_len len[qual, int32]
qual ptr[in, usb_qualifier_descriptor]
bos_len len[bos, int32]
bos ptr[in, usb_bos_descriptor]
strs_len len[strs, int32]
strs array[vusb_connect_string_descriptor]
} [packed]
```
So, the third argument of `syz_usb_connect` is `conn_descs ptr[in, vusb_connect_descriptors]`. Therefore I should probably pass either `0` or something like `&AUTO={0, 0, 0, 0, 0, []}`. But hang on, where do I pass the actual raw descriptors?
Okay, let's look at the full signature of `syz_usb_connect`:
`syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev, int32], dev ptr[in, string], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb`
Wait, the third argument is `dev ptr[in, string]`! Okay, so `&AUTO="1201..."` *is* correct for the third argument. Why did it say "wrong string arg" then?
Aha! `dev ptr[in, string]` expects a string, and `&AUTO="1201..."` is a pointer to a string. Actually, `&AUTO="1201..."` is a pointer to a *hex* string. That's probably the problem. Maybe I need to use `&AUTO='\x12\x01...'`? Let me double-check the documentation on how strings should be handled.
Okay, the docs say `string-arg = "'" escaped-string "'" | "\"" escaped-string "\"" | "\"$" escaped-string "\""`.
Right, `&AUTO="01010101"` *is* a pointer to a string. But, again, the `syz_usb_connect` signature is:
`syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev, int32], dev ptr[in, string], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb`
So `dev` is `ptr[in, string]`. If I use `&AUTO='\x12\x01...'`, that *is* a pointer to a string, and a valid one, I think.
Alright, let's try `&AUTO='\x12\x01\x00\x02\x00\x00\x00\x40\x40\x20\x00\x72\x00\x00\x01\x02\x03\x01\x09\x02\x19\x00\x01\x01\x00\x80\xfa\x09\x04\x00\x00\x01\xff\x00\x00\x00\x07\x05\x81\x02\x00\x02\x00'` (with single quotes) and see if that works.
|
| 107/2 |
2026/07/30 12:28 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0x2b, &AUTO='\x12\x01\x00\x02\x00\x00\x00\x40\x40\x20\x00\x72\x00\x00\x01\x02\x03\x01\x09\x02\x19\x00\x01\x01\x00\x80\xfa\x09\x04\x00\x00\x01\xff\x00\x00\x00\x07\x05\x81\x02\x00\x02\x00', 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r7 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r8 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r9 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r10 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r11 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r12 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r13 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r14 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r15 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r16 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r17 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r18 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r9, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r10, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r11, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r12, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r15, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r16, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r17, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r18, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 108/2 |
2026/07/30 12:28 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 38991
output: 1277
thoughts: 756
Thoughts: **Debugging a Syzkaller String Argument**
Okay, let's see. Right, the third argument for this function is `dev ptr[in, string]`. Hmm, wait. I need to remember the syzkaller string literal syntax. I know that `&AUTO="1201..."` is for hex strings, but I'm wondering if the parser might be expecting a struct or array instead? No, it's definitely a `string`. Okay, so if it's a `string` maybe I can skip the `&AUTO=`, but no, `ptr[in, string]` *needs* `&AUTO=...` or `&(0x7f...)=...`.
Let me see how this function, `syz_usb_connect`, is used elsewhere to get some ideas. Wait, right, it's defined in `vusb.txt`. Let me check... Ah, here it is: `dev ptr[in, string]`, confirms what I suspected. Okay.
Maybe the string is incorrectly formatted. Let's try this: `&(0x7f0000000000)='\x12\x01\x00\x02\x00...'`. Ah, that failed with a "wrong string arg" error. Let's consult the documentation: `string-arg = "'" escaped-string "'" | "\"" escaped-string "\"" | "\"$" escaped-string "\""`.
Okay, so maybe the hex string needs to be `&AUTO="1201000200000040..."`? I tried that, it failed too. Let's try again with the documentation in mind. Wait, what if I simply try `&AUTO=""`, which does not work. Hmm, no, I need the actual byte values.
Ah, in syzkaller, isn't it true that a hex string is denoted by `$"1201..."`? Let's verify... yes, `"\"$" escaped-string "\""` means `"$1201..."`. Okay, let's try this: `&AUTO="$1201000200000040402000720000010203010902190001010080fa0904000001ff00000007058102000200"`.
|
| 109/2 |
2026/07/30 12:29 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0x2b, &AUTO="$1201000200000040402000720000010203010902190001010080fa0904000001ff00000007058102000200", 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r7 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r8 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r9 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r10 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r11 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r12 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r13 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r14 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r15 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r16 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r17 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r18 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r9, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r10, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r11, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r12, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r15, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r16, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r17, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r18, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 110/2 |
2026/07/30 12:29 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 41709
output: 19
thoughts: 514
Thoughts: **Debugging a Syzkaller USB Fuzzing Scenario**
Okay, so I'm trying to craft a specific USB connection setup using Syzkaller. My initial thought was, "Can I just use `&AUTO=""` and then manually set the bytes with `syz_usb_connect`?" Seems like a good way to be explicit. But then I remembered, wait, isn't the string syntax for `&AUTO` something like `"01010101"`? And isn't that a *string*? Right, the documentation shows that `&AUTO` is used with `write`, like `write(r0, &AUTO="01010101", 0x4)`. That's not quite what I'm after here.
So, if I want to pass actual hex bytes, I should be using `&AUTO='\x12\x01...'`. That makes sense. But, I just got a "wrong string arg" error. Let me check the error message again... Ah, there it is!
`line #1:36: r0 = syz_usb_connect(3, 0x2b, &AUTO=<<<!!ERROR!!>>>'\x12\x01\x00\x02\x00\x00\x00\x40\x40\x20\x00\x72\x00\x00\x01\x02\x03\x01\x09\x02\x19\x00\x01\x01\x00\x80\xfa\x09\x04\x00\x00\x01\xff\x00\x00\x00\x07\x05\x81\x02\x00\x02\x00', 0)`
Right. The error is still "wrong string arg" but let's carefully consider the structure. The issue is with the third argument to `syz_usb_connect`, which is a `dev ptr[in, string]`. I need to figure out how Syzkaller expects to handle that.
Aha! `dev` is a pointer to a string. So, maybe I don't need `&AUTO=` at all? But I am fairly certain that pointer arguments to Syzkaller need to start with `&` or be `AUTO` or `0`. Shoot, what if I could pass an array? Like `&AUTO={'12', '01', ...}`? No, I'm pretty sure that would also trigger a similar error.
Okay, time to consult `vusb.txt` and see exactly how the `dev` parameter is defined. Hopefully, there is more clarity there to understand the correct syntax.
|
| 111/2 |
2026/07/30 12:29 |
tool |
read-description |
0m
Args:
Results: map[Output:# Copyright 2019 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
include <linux/types.h>
include <linux/byteorder/generic.h>
include <uapi/linux/usb/ch9.h>
include <uapi/linux/usb/ch11.h>
include <uapi/linux/usb/midi.h>
include <uapi/linux/usb/audio.h>
include <linux/usb/audio-v2.h>
include <linux/usb/audio-v3.h>
include <uapi/linux/hid.h>
include <linux/hid.h>
include <uapi/linux/usb/cdc.h>
include <uapi/linux/if_ether.h>
include <linux/interrupt.h>
include <linux/usb/cdc_ncm.h>
include <drivers/net/usb/asix.h>
# This is a special fd for USB fuzzing and should only be used with syz_usb_* pseudo-syscalls.
# We don't inherit it from the fd resource, to discourage syzkaller calling raw ioctls on it.
resource fd_usb[int32]: -1
# These are generic pseudo-syscalls for emulating arbitrary USB devices.
# They are mostly targeted to cover the enumeration process.
syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io(fd fd_usb, descs ptr[in, vusb_descriptors], resps ptr[in, vusb_responses]) (timeout[300], remote_cover)
syz_usb_ep_write(fd fd_usb, ep int8, len len[data], data ptr[in, array[int8, 0:256]]) (timeout[300], remote_cover)
syz_usb_ep_read(fd fd_usb, ep int8, len len[data], data buffer[out]) (timeout[300], remote_cover)
syz_usb_disconnect(fd fd_usb) (timeout[300], remote_cover)
usb_device_speed = USB_SPEED_UNKNOWN, USB_SPEED_LOW, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_WIRELESS, USB_SPEED_SUPER, USB_SPEED_SUPER_PLUS
# TODO: consider patching idVendor and idProduct for all class specific descriptions in Go code to cover more drivers.
# TODO: custom syz_usb_ep_write() descriptions for all class specific descriptions.
# TODO: consider adding custom vusb_connect_descriptors definitions to all class specific descriptions.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
type usb_device_descriptor_verbose_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] {
bLength const[USB_DT_DEVICE_SIZE, int8]
bDescriptorType const[USB_DT_DEVICE, int8]
bcdUSB USB
bDeviceClass const[CLASS, int8]
bDeviceSubClass const[SUBCLASS, int8]
bDeviceProtocol const[PROTOCOL, int8]
bMaxPacketSize0 PACKET
idVendor const[VENDOR, int16]
idProduct const[PRODUCT, int16]
bcdDevice const[DEVICE, int16]
iManufacturer const[1, int8]
iProduct const[2, int8]
iSerialNumber const[3, int8]
bNumConfigurations len[configs, int8]
configs CFS
} [packed]
type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[flags[usb_versions, int16], CLASS, SUBCLASS, PROTOCOL, flags[usb_device_max_packet_sizes, int8], VENDOR, PRODUCT, DEVICE, CFS]
type usb_device_descriptor_fixed_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[const[USB, int16], CLASS, SUBCLASS, PROTOCOL, const[PACKET, int8], VENDOR, PRODUCT, DEVICE, CFS]
usb_versions = 0x110, 0x200, 0x201, 0x250, 0x300, 0x310
# https://elixir.bootlin.com/linux/v5.1.7/source/drivers/usb/core/hub.c#L4661
usb_device_max_packet_sizes = 8, 16, 32, 64, 255
type usb_config_descriptor_verbose_t[NUM, IFSNUM, ICONFIG, ATTRS, POWER, EXTRA, IFS] {
bLength const[USB_DT_CONFIG_SIZE, int8]
bDescriptorType const[USB_DT_CONFIG, int8]
wTotalLength len[parent, int16]
bNumInterfaces IFSNUM
bConfigurationValue NUM
iConfiguration ICONFIG
bmAttributes ATTRS
bMaxPower POWER
extra EXTRA
interfaces IFS
} [packed]
type usb_config_descriptor_t[NUM, IFSNUM, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, void, IFS]
type usb_config_descriptor_ifaces_array_t[NUM, IFS] usb_config_descriptor_t[NUM, len[interfaces, int8], IFS]
type usb_config_descriptor_fixed_t[NUM, IFSNUM, ATTRS, POWER, IFS] usb_config_descriptor_verbose_t[const[NUM, int8], const[IFSNUM, int8], const[0, int8], const[ATTRS, int8], const[POWER, int8], void, IFS]
type usb_config_descriptor_extra_t[NUM, IFSNUM, EXTRA, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, EXTRA, IFS]
type usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, IIF, EXTRA, EPS] {
bLength const[USB_DT_INTERFACE_SIZE, int8]
bDescriptorType const[USB_DT_INTERFACE, int8]
bInterfaceNumber IFNUM
bAlternateSetting ALTNUM
bNumEndpoints EPSNUM
bInterfaceClass CLASS
bInterfaceSubClass SUBCLASS
bInterfaceProtocol PROTOCOL
iInterface IIF
extra EXTRA
endpoints EPS
} [packed]
type usb_interface_descriptor_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, int8, EXTRA, EPS]
type usb_interface_descriptor_eps_array_t[IFNUM, ALTNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_t[IFNUM, ALTNUM, len[endpoints, int8], CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS]
type usb_interface_descriptor_fixed_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[const[IFNUM, int8], const[ALTNUM, int8], const[EPSNUM, int8], const[CLASS, int8], const[SUBCLASS, int8], const[PROTOCOL, int8], const[0, int8], EXTRA, EPS]
# TODO: non-audio endpoints have USB_DT_ENDPOINT_SIZE.
type usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, PACKET, INTERVAL, REFRESH, SYNCH, EXTRA] {
bLength const[USB_DT_ENDPOINT_AUDIO_SIZE, int8]
bDescriptorType const[USB_DT_ENDPOINT, int8]
bEndpointAddress ADDR
bmAttributes ATTRS
wMaxPacketSize PACKET
bInterval INTERVAL
bRefresh REFRESH
bSynchAddress SYNCH
extra EXTRA
} [packed]
type usb_endpoint_descriptor_t[ADDR, ATTRS, EXTRA] usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, EXTRA]
type usb_endpoint_descriptor_fixed_t[ADDR, ATTRS, PACKET, INTERVAL, EXTRA] usb_endpoint_descriptor_verbose_t[const[ADDR, int8], const[ATTRS, int8], const[PACKET, int16], const[INTERVAL, int8], const[0, int8], const[0, int8], EXTRA]
# TODO: dummy driver has complex requirements for packet sizes, account for those:
# https://elixir.bootlin.com/linux/v5.3.6/source/drivers/usb/gadget/udc/dummy_hcd.c#L497
usb_endpoint_max_packet_sizes = 8, 16, 32, 64, 512, 1023, 1024
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Generic USB device, configuration, interface and endpoint descriptors.
# We only support one configuration per device.
# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct
# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]]
} [packed]
usb_config_descriptor {
inner usb_config_descriptor_ifaces_array_t[int8, array[usb_interface_descriptor, 1:4]]
} [packed]
usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY
# bInterfaceNumber, bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol
# are patched by Go code, see sys/linux/init_vusb.go.
usb_interface_descriptor {
inner usb_interface_descriptor_eps_array_t[int8, int8, const[0, int8], const[0, int8], const[0, int8], array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
} [packed]
usb_endpoint_descriptor {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], array[usb_endpoint_extra_descriptor, 0:2]]
} [packed]
usb_endpoint_addresses = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, USB_DIR_OUT, USB_DIR_IN
usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK
vusb_connect_descriptors {
qual_len len[qual, int32]
qual ptr[in, usb_qualifier_descriptor]
bos_len len[bos, int32]
bos ptr[in, usb_bos_descriptor]
strs_len len[strs, int32]
strs array[vusb_connect_string_descriptor]
} [packed]
vusb_connect_string_descriptor {
len len[str, int32]
str ptr[in, usb_string_descriptor]
} [packed]
vusb_descriptors {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]]
hub_hs ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_HUB, usb_hub_descriptor_hs]]
hub_ss ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_SS_HUB, usb_hub_descriptor_ss]]
} [packed]
vusb_descriptor_generic {
req_type flags[usb_request_types, int8]
desc_type flags[usb_descriptor_types, int8]
len bytesize[data, int32]
data usb_generic_descriptor
} [packed]
usb_request_types = USB_TYPE_STANDARD, USB_TYPE_CLASS, USB_TYPE_VENDOR
type vusb_descriptor_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# TODO: consider doing lookups based on USB_RECIP values.
vusb_responses {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
get_interface ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
get_configuration ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
# TODO: move these into custom descriptions for hub class when they are added.
hub_USB_REQ_GET_STATUS_hub ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_hub_status]]
hub_USB_REQ_GET_STATUS_port ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_port_status]]
# TODO: move these into custom descriptions for asix driver when they are added.
asix_AX_CMD_READ_MII_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MII_REG, int16]]
asix_AX_CMD_STATMNGSTS_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_STATMNGSTS_REG, int8]]
asix_AX_CMD_READ_EEPROM ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_EEPROM, array[int8, 2]]]
asix_AX_CMD_READ_RX_CTL ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_RX_CTL, int16]]
asix_AX_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_NODE_ID, mac_addr]]
asix_AX88172_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX88172_CMD_READ_NODE_ID, mac_addr]]
asix_AX_CMD_READ_PHY_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_PHY_ID, array[int8, 2]]]
asix_AX_CMD_READ_MEDIUM_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MEDIUM_STATUS, int16]]
asix_AX_CMD_READ_MONITOR_MODE ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MONITOR_MODE, int8]]
asix_AX_CMD_READ_GPIOS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_GPIOS, int8]]
asix_AX_CMD_SW_PHY_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_SW_PHY_STATUS, int8]]
} [packed]
vusb_response_generic {
type flags[usb_request_types, int8]
req flags[usb_requests, int8]
len bytesize[data, int32]
data array[int8, 0:256]
} [packed]
usb_requests = USB_REQ_GET_STATUS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, USB_REQ_SET_ADDRESS, USB_REQ_GET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR, USB_REQ_GET_CONFIGURATION, USB_REQ_SET_CONFIGURATION, USB_REQ_GET_INTERFACE, USB_REQ_SET_INTERFACE, USB_REQ_SYNCH_FRAME, USB_REQ_SET_SEL, USB_REQ_SET_ISOCH_DELAY, USB_REQ_SET_ENCRYPTION, USB_REQ_GET_ENCRYPTION, USB_REQ_RPIPE_ABORT, USB_REQ_SET_HANDSHAKE, USB_REQ_RPIPE_RESET, USB_REQ_GET_HANDSHAKE, USB_REQ_SET_CONNECTION, USB_REQ_SET_SECURITY_DATA, USB_REQ_GET_SECURITY_DATA, USB_REQ_SET_WUSB_DATA, USB_REQ_LOOPBACK_DATA_WRITE, USB_REQ_LOOPBACK_DATA_READ, USB_REQ_SET_INTERFACE_DS, USB_REQ_GET_PARTNER_PDO, USB_REQ_GET_BATTERY_STATUS, USB_REQ_SET_PDO, USB_REQ_GET_VDM, USB_REQ_SEND_VDM
type vusb_response_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested by the kernel before the SET_CONFIGURATION request.
# TODO: figure out when is the USB_DT_OTG descriptor used.
# TODO: figure out when is the USB_DT_INTERFACE_ASSOCIATION descriptor used.
# TODO: figure out when is the USB_DT_BOS descriptor used.
type usb_string_descriptor_t[DATA] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_STRING, int8]
data DATA
} [packed]
usb_string_descriptor [
lang_id usb_string_descriptor_t[flags[usb_lang_ids, int16]]
string usb_string_descriptor_t[array[int8, 0:256]]
] [varlen]
usb_lang_ids = 0x436, 0x41c, 0x401, 0x801, 0xc01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001, 0x42b, 0x44d, 0x42c, 0x82c, 0x42d, 0x423, 0x445, 0x402, 0x455, 0x403, 0x404, 0x804, 0xc04, 0x1004, 0x1404, 0x41a, 0x405, 0x406, 0x413, 0x813, 0x409, 0x809, 0xc09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x425, 0x438, 0x429, 0x40b, 0x40c, 0x80c, 0xc0c, 0x100c, 0x140c, 0x180c, 0x437, 0x407, 0x807, 0xc07, 0x1007, 0x1407, 0x408, 0x447, 0x40d, 0x439, 0x40e, 0x40f, 0x421, 0x410, 0x810, 0x411, 0x44b, 0x860, 0x43f, 0x457, 0x412, 0x812, 0x426, 0x427, 0x827, 0x42f, 0x43e, 0x83e, 0x44c, 0x458, 0x44e, 0x861, 0x414, 0x814, 0x448, 0x415, 0x416, 0x816, 0x446, 0x418, 0x419, 0x44f, 0xc1a, 0x81a, 0x459, 0x41b, 0x424, 0x40a, 0x80a, 0xc0a, 0x100a, 0x140a, 0x180a, 0x1c0a, 0x200a, 0x240a, 0x280a, 0x2c0a, 0x300a, 0x340a, 0x380a, 0x3c0a, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a, 0x430, 0x441, 0x41d, 0x81d, 0x449, 0x444, 0x44a, 0x41e, 0x41f, 0x422, 0x420, 0x820, 0x443, 0x843, 0x42a, 0x4ff, 0xf0ff, 0xf4ff, 0xf8ff, 0xfcff
usb_qualifier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_QUALIFIER, int8]
bcdUSB flags[usb_versions, int16]
bDeviceClass int8
bDeviceSubClass int8
bDeviceProtocol int8
bMaxPacketSize0 flags[usb_device_max_packet_sizes, int8]
bNumConfigurations int8
bRESERVED const[0, int8]
} [packed]
usb_bos_descriptor {
bLength const[USB_DT_BOS_SIZE, int8]
bDescriptorType const[USB_DT_BOS, int8]
wTotalLength len[parent, int16]
bNumDeviceCaps len[caps, int8]
caps array[usb_dev_cap, 0:6]
} [packed]
usb_dev_cap [
generic usb_generic_cap_descriptor
wireless usb_wireless_cap_descriptor
ext_cap usb_ext_cap_descriptor
ss_cap usb_ss_cap_descriptor
ss_container_id usb_ss_container_id_descriptor
ssp_cap usb_ssp_cap_descriptor
ptm_cap usb_ptm_cap_descriptor
] [varlen]
usb_generic_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType flags[usb_capability_types, int8]
data array[int8, 0:256]
} [packed]
usb_capability_types = USB_CAP_TYPE_WIRELESS_USB, USB_CAP_TYPE_EXT, USB_SS_CAP_TYPE, USB_SSP_CAP_TYPE, CONTAINER_ID_TYPE, USB_PTM_CAP_TYPE
usb_wireless_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_WIRELESS_USB, int8]
bmAttributes flags[usb_wireless_cap_attributes, int8]
wPHYRates flags[usb_wireless_cap_phyrates, int16]
bmTFITXPowerInfo int8
bmFFITXPowerInfo int8
bmBandGroup int16
bReserved int8
} [packed]
usb_wireless_cap_attributes = USB_WIRELESS_P2P_DRD, USB_WIRELESS_BEACON_MASK, USB_WIRELESS_BEACON_SELF, USB_WIRELESS_BEACON_DIRECTED, USB_WIRELESS_BEACON_NONE
usb_wireless_cap_phyrates = USB_WIRELESS_PHY_53, USB_WIRELESS_PHY_80, USB_WIRELESS_PHY_107, USB_WIRELESS_PHY_160, USB_WIRELESS_PHY_200, USB_WIRELESS_PHY_320, USB_WIRELESS_PHY_400, USB_WIRELESS_PHY_480
usb_ext_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_EXT, int8]
bmAttributes1 flags[usb_ext_cap_attributes, int32:8]
bmAttributes2 int32:4
bmAttributes3 int32:4
bmAttributes4 int32:16
} [packed]
usb_ext_cap_attributes = USB_LPM_SUPPORT, USB_BESL_SUPPORT, USB_BESL_BASELINE_VALID, USB_BESL_DEEP_VALID
usb_ss_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SS_CAP_TYPE, int8]
bmAttributes flags[usb_ss_cap_attributes, int8]
wSpeedSupported flags[usb_ss_cap_speed, int16]
bFunctionalitySupport int8
bU1devExitLat int8
bU2DevExitLat int16
} [packed]
usb_ss_cap_attributes = USB_LTM_SUPPORT
usb_ss_cap_speed = USB_LOW_SPEED_OPERATION, USB_FULL_SPEED_OPERATION, USB_HIGH_SPEED_OPERATION, USB_5GBPS_OPERATION
usb_ss_container_id_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[CONTAINER_ID_TYPE, int8]
bReserved int8
ContainerID array[int8, 16]
} [packed]
usb_ssp_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SSP_CAP_TYPE, int8]
bReserved int8
bmAttributesSublinkSpeeds len[bmSublinkSpeedAttr, int32:5]
bmAttributesSpeedIDs int32:27
wFunctionalitySupport flags[usb_ssp_cap_funcs, int16]
wReserved int16
bmSublinkSpeedAttr array[flags[usb_ssp_cap_sublink_speeds, int32], 0:6]
} [packed]
usb_ssp_cap_funcs = USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, USB_SSP_MIN_RX_LANE_COUNT, USB_SSP_MIN_TX_LANE_COUNT
usb_ssp_cap_sublink_speeds = USB_SSP_SUBLINK_SPEED_SSID, USB_SSP_SUBLINK_SPEED_LSE, USB_SSP_SUBLINK_SPEED_ST, USB_SSP_SUBLINK_SPEED_RSVD, USB_SSP_SUBLINK_SPEED_LP, USB_SSP_SUBLINK_SPEED_LSM
usb_ptm_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_PTM_CAP_TYPE, int8]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Extra USB descriptors that come after an interface or an endpoint descriptor.
# TODO: consider removing class specific descriptors here for described classes.
usb_interface_extra_descriptor [
generic usb_generic_descriptor
hid_hid usb_hid_descriptor_hid
cdc_ecm usb_cdc_header_ecm
cdc_ncm usb_cdc_header_ncm
uac_control uac_control_iface_extra_descriptors
uac_as uac_as_iface_extra_descriptors
] [varlen]
usb_endpoint_extra_descriptor [
generic usb_generic_descriptor
uac_iso uac_iso_endpoint_descriptor
] [varlen]
usb_generic_descriptor {
bLength len[parent, int8]
bDescriptorType flags[usb_descriptor_types, int8]
data array[int8, 0:256]
} [packed]
usb_descriptor_types = USB_DT_DEVICE, USB_DT_CONFIG, USB_DT_STRING, USB_DT_INTERFACE, USB_DT_ENDPOINT, USB_DT_DEVICE_QUALIFIER, USB_DT_OTHER_SPEED_CONFIG, USB_DT_INTERFACE_POWER, USB_DT_OTG, USB_DT_DEBUG, USB_DT_INTERFACE_ASSOCIATION, USB_DT_SECURITY, USB_DT_KEY, USB_DT_ENCRYPTION_TYPE, USB_DT_BOS, USB_DT_DEVICE_CAPABILITY, USB_DT_WIRELESS_ENDPOINT_COMP, USB_DT_WIRE_ADAPTER, USB_DT_RPIPE, USB_DT_CS_RADIO_CONTROL, USB_DT_PIPE_USAGE, USB_DT_SS_ENDPOINT_COMP, USB_DT_SSP_ISOC_ENDPOINT_COMP, HID_DT_HID, HID_DT_REPORT, HID_DT_PHYSICAL
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested after the SET_CONFIGURATION request.
usb_hub_descriptor_hs {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
DeviceRemovable array[int8, USB_HUB_PORTS_BITS]
PortPwrCtrlMask array[int8, USB_HUB_PORTS_BITS]
} [packed]
usb_hub_descriptor_ss {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_SS_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
bHubHdrDecLat int8
wHubDelay int16
DeviceRemovable int16
} [packed]
define USB_HUB_PORTS_BITS ((USB_MAXCHILDREN + 1 + 7) / 8)
usb_hub_characteristics = HUB_CHAR_LPSM, HUB_CHAR_COMMON_LPSM, HUB_CHAR_INDV_PORT_LPSM, HUB_CHAR_NO_LPSM, HUB_CHAR_COMPOUND, HUB_CHAR_OCPM, HUB_CHAR_COMMON_OCPM, HUB_CHAR_INDV_PORT_OCPM, HUB_CHAR_NO_OCPM, HUB_CHAR_TTTT, HUB_CHAR_PORTIND
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Replies to USB control requests requested after the SET_CONFIGURATION request.
usb_port_status {
wPortStatus flags[usb_port_status_flags, int16]
wPortChange flags[usb_port_change_flags, int16]
dwExtPortStatus array[flags[usb_ext_port_status_flags, int32], 0:1]
} [packed]
usb_port_status_flags = USB_PORT_STAT_CONNECTION, USB_PORT_STAT_ENABLE, USB_PORT_STAT_SUSPEND, USB_PORT_STAT_OVERCURRENT, USB_PORT_STAT_RESET, USB_PORT_STAT_L1, USB_PORT_STAT_POWER, USB_PORT_STAT_LOW_SPEED, USB_PORT_STAT_HIGH_SPEED, USB_PORT_STAT_TEST, USB_PORT_STAT_INDICATOR, USB_PORT_STAT_LINK_STATE, USB_SS_PORT_STAT_POWER, USB_SS_PORT_STAT_SPEED, USB_PORT_STAT_SPEED_5GBPS, USB_SS_PORT_LS_U0, USB_SS_PORT_LS_U1, USB_SS_PORT_LS_U2, USB_SS_PORT_LS_U3, USB_SS_PORT_LS_SS_DISABLED, USB_SS_PORT_LS_RX_DETECT, USB_SS_PORT_LS_SS_INACTIVE, USB_SS_PORT_LS_POLLING, USB_SS_PORT_LS_RECOVERY, USB_SS_PORT_LS_HOT_RESET, USB_SS_PORT_LS_COMP_MOD, USB_SS_PORT_LS_LOOPBACK
usb_port_change_flags = USB_PORT_STAT_C_CONNECTION, USB_PORT_STAT_C_ENABLE, USB_PORT_STAT_C_SUSPEND, USB_PORT_STAT_C_OVERCURRENT, USB_PORT_STAT_C_RESET, USB_PORT_STAT_C_L1, USB_PORT_STAT_C_BH_RESET, USB_PORT_STAT_C_LINK_STATE, USB_PORT_STAT_C_CONFIG_ERROR
usb_ext_port_status_flags = USB_EXT_PORT_STAT_RX_SPEED_ID, USB_EXT_PORT_STAT_TX_SPEED_ID, USB_EXT_PORT_STAT_RX_LANES, USB_EXT_PORT_STAT_TX_LANES
usb_hub_status {
wHubStatus flags[usb_hub_status_flags, int16]
wHubChange flags[usb_hub_change_flags, int16]
} [packed]
usb_hub_status_flags = HUB_STATUS_LOCAL_POWER, HUB_STATUS_OVERCURRENT
usb_hub_change_flags = HUB_CHANGE_LOCAL_POWER, HUB_CHANGE_OVERCURRENT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# HID device class specific descriptions.
# https://www.usb.org/sites/default/files/documents/hid1_11.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/usbhid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/hid.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_hid.c
# Connected HID devices are known to create the following /dev/ files:
# /dev/hidraw#, /dev/usb/hiddev# and /dev/input/event#.
resource fd_usb_hid[fd_usb]
syz_usb_connect$hid(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_hid], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_hid (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$hid(fd fd_usb_hid, descs ptr[in, vusb_descriptors_hid], resps ptr[in, vusb_responses_hid]) (timeout[300], remote_cover)
# idVendor and idProduct are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor_hid {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 64, array[usb_config_descriptor_hid, 1]]
} [packed]
usb_config_descriptor_hid {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_hid, 1]]
} [packed]
usb_interface_descriptor_hid {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_HID, int8], const[USB_INTERFACE_SUBCLASS_BOOT, int8], flags[usb_hid_protocols, int8], usb_hid_descriptor_hid, usb_endpoint_descriptors_hid]
} [packed]
usb_hid_protocols = USB_INTERFACE_PROTOCOL_KEYBOARD, USB_INTERFACE_PROTOCOL_MOUSE
usb_endpoint_descriptors_hid {
in usb_endpoint_descriptor_hid_in
out array[usb_endpoint_descriptor_hid_out, 0:1]
} [packed]
usb_endpoint_descriptor_hid_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_IN_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_hid_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_OUT_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_HID_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_HID_IN_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_HID_OUT_ADDRESS (2)
vusb_descriptors_hid {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
# For unknown reasons these are requested as USB_TYPE_STANDARD and not as USB_TYPE_CLASS.
# Linux doesn't request HID_DT_HID, but some hosts might do that.
HID_DT_REPORT ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]]
HID_DT_HID ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_HID, usb_hid_descriptor_hid]]
} [packed]
vusb_responses_hid {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
HID_REQ_GET_REPORT ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_REPORT, array[int8, 0:256]]]
HID_REQ_GET_PROTOCOL ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_PROTOCOL, int8]]
} [packed]
# USB HID specifications allows for multiple report and physical descriptors
# to be present, but I don't see any support for them in the Linux kernel,
# except for a single report descriptor.
usb_hid_descriptor_hid {
bLength len[parent, int8]
bDescriptorType const[HID_DT_HID, int8]
bcdHID int16
bCountryCode int8
bNumDescriptors const[1, int8]
report_desc usb_hid_class_descriptor_report
} [packed]
usb_hid_class_descriptor_report {
bDescriptorType const[HID_DT_REPORT, int8]
wDescriptorLength int16[0:HID_MAX_DESCRIPTOR_SIZE]
} [packed]
# TODO: it's hard to describe the REPORT descriptor structure via syzkaller
# descriptions, so consider generating it in Go code.
# TODO: the length of REPORT descriptor must match the value in HID descriptor.
# TODO: there are vendor specific REPORT descriptor formats (Logitech HID++).
# Linux HID stack doesn't support long items.
hid_descriptor_report {
items array[hid_report_item_short]
} [packed]
type hid_report_item_short_012_t[TYPE, TAGS] {
bSize len[data, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 0:2]
} [packed]
type hid_report_item_short_4_t[TYPE, TAGS] {
bSize const[3, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 4]
} [packed]
type hid_report_item_short_t[TYPE, TAGS] [
item_012 hid_report_item_short_012_t[TYPE, TAGS]
item_4 hid_report_item_short_4_t[TYPE, TAGS]
] [varlen]
hid_report_item_short [
main hid_report_item_short_t[HID_ITEM_TYPE_MAIN, hid_report_item_main_tags]
global hid_report_item_short_t[HID_ITEM_TYPE_GLOBAL, hid_report_item_global_tags]
local hid_report_item_short_t[HID_ITEM_TYPE_LOCAL, hid_report_item_local_tags]
] [varlen]
hid_report_item_main_tags = HID_MAIN_ITEM_TAG_INPUT, HID_MAIN_ITEM_TAG_OUTPUT, HID_MAIN_ITEM_TAG_FEATURE, HID_MAIN_ITEM_TAG_BEGIN_COLLECTION, HID_MAIN_ITEM_TAG_END_COLLECTION
hid_report_item_global_tags = HID_GLOBAL_ITEM_TAG_USAGE_PAGE, HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT, HID_GLOBAL_ITEM_TAG_UNIT, HID_GLOBAL_ITEM_TAG_REPORT_SIZE, HID_GLOBAL_ITEM_TAG_REPORT_ID, HID_GLOBAL_ITEM_TAG_REPORT_COUNT, HID_GLOBAL_ITEM_TAG_PUSH, HID_GLOBAL_ITEM_TAG_POP
hid_report_item_local_tags = HID_LOCAL_ITEM_TAG_USAGE, HID_LOCAL_ITEM_TAG_USAGE_MINIMUM, HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX, HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM, HID_LOCAL_ITEM_TAG_STRING_INDEX, HID_LOCAL_ITEM_TAG_STRING_MINIMUM, HID_LOCAL_ITEM_TAG_STRING_MAXIMUM, HID_LOCAL_ITEM_TAG_DELIMITER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# PRINTER device class specific descriptions.
# https://www.usb.org/sites/default/files/usbprint11a021811.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/class/usblp.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/printer.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_printer.c
# Connected PRINTER devices are known to create the following /dev/ files:
# /dev/usb/lp#.
# TODO: write descriptions for those.
# drivers/usb/class/usblp.c
define USBLP_REQ_GET_ID 0x00
define USBLP_REQ_GET_STATUS 0x01
define USBLP_REQ_RESET 0x02
define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00
define USBLP_FIRST_PROTOCOL 1
define USBLP_LAST_PROTOCOL 3
resource fd_usb_printer[fd_usb]
syz_usb_connect$printer(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_printer], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_printer (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$printer(fd fd_usb_printer, descs ptr[in, vusb_descriptors_printer], resps ptr[in, vusb_responses_printer]) (timeout[300], remote_cover)
usb_device_descriptor_printer {
inner usb_device_descriptor_t[0, 0, 0, 0x525, 0xa4a8, 64, array[usb_config_descriptor_printer, 1]]
} [packed]
usb_config_descriptor_printer {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_printer, 1]]
} [packed]
usb_interface_descriptor_printer {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_PRINTER, int8], const[1, int8], int8[USBLP_FIRST_PROTOCOL:USBLP_LAST_PROTOCOL], void, usb_endpoint_descriptors_printer]
} [packed]
usb_endpoint_descriptors_printer {
in usb_endpoint_descriptor_printer_out
out array[usb_endpoint_descriptor_printer_in, 0:1]
} [packed]
usb_endpoint_descriptor_printer_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_OUT_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_printer_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_IN_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_PRINTER_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_PRINTER_OUT_ADDRESS (1)
define USB_ENDPOINT_PRINTER_IN_ADDRESS (2 | USB_DIR_IN)
vusb_descriptors_printer {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_printer {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USBLP_REQ_GET_ID ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_ID, usb_printer_get_id_response]]
USBLP_REQ_GET_STATUS ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_STATUS, int8]]
USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, int8]]
} [packed]
usb_printer_get_id_response {
length len[id, int16be]
id array[int8, 0:256]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC ECM (Ethernet) device class specific descriptions.
# https://www.usb.org/document-library/class-definitions-communication-devices-12
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ecm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/u_ether.c
# Connected CDC ECM devices are known to create usbN network interfaces.
# TODO: write descriptions for those.
resource fd_usb_cdc_ecm[fd_usb]
syz_usb_connect$cdc_ecm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ecm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ecm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ecm(fd fd_usb_cdc_ecm, descs ptr[in, vusb_descriptors_cdc_ecm], resps ptr[in, vusb_responses_cdc_ecm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ecm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ecm, 1]]
} [packed]
usb_config_descriptor_cdc_ecm {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_cdc_ecm, 1]]
} [packed]
# Per specification CDC ECM devices have two interfaces (control and data),
# but here we're merging them into one for simplicity since Linux supports that.
usb_interface_descriptor_cdc_ecm {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[2:3], const[USB_CLASS_COMM, int8], const[USB_CDC_SUBCLASS_ETHERNET, int8], const[USB_CDC_PROTO_NONE, int8], usb_cdc_header_ecm, usb_endpoint_descriptors_cdc_ecm]
} [packed]
usb_endpoint_descriptors_cdc_ecm {
notify array[usb_endpoint_descriptor_cdc_ecm_notify, 0:1]
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
usb_endpoint_descriptor_cdc_ecm_notify {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_IN_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_OUT_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_OUT_ADDRESS (3)
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L155
usb_cdc_header_ecm {
union usb_cdc_union_desc_t[0, 0]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
other array[usb_cdc_header_ecm_other, 0:6]
} [packed]
usb_cdc_header_ecm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
ncm usb_cdc_ncm_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
usb_cdc_header_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_HEADER_TYPE, int8]
bcdCDC int16
} [packed]
usb_cdc_call_mgmt_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_CALL_MANAGEMENT_TYPE, int8]
bmCapabilities flags[usb_cdc_call_mgmt_caps, int8]
bDataInterface int8
} [packed]
usb_cdc_call_mgmt_caps = USB_CDC_CALL_MGMT_CAP_CALL_MGMT, USB_CDC_CALL_MGMT_CAP_DATA_INTF
usb_cdc_acm_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ACM_TYPE, int8]
bmCapabilities flags[usb_cdc_acm_caps, int8]
} [packed]
usb_cdc_acm_caps = USB_CDC_COMM_FEATURE, USB_CDC_CAP_LINE, USB_CDC_CAP_BRK, USB_CDC_CAP_NOTIFY
type usb_cdc_union_desc_t[MASTER, SLAVE] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_UNION_TYPE, int8]
bMasterInterface0 const[MASTER, int8]
bSlaveInterface0 const[SLAVE, int8]
slave_interfaces array[int8, 0:6]
} [packed]
usb_cdc_country_functional_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_COUNTRY_TYPE, int8]
iCountryCodeRelDate int8
wCountyCode0 int16
country_codes array[int16, 0:6]
} [packed]
usb_cdc_network_terminal_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NETWORK_TERMINAL_TYPE, int8]
bEntityId int8
iName int8
bChannelIndex int8
bPhysicalInterface int8
} [packed]
usb_cdc_ether_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ETHERNET_TYPE, int8]
iMACAddress const[1, int8]
bmEthernetStatistics int32
wMaxSegmentSize int16
wNumberMCFilters int16
bNumberPowerFilters int8
} [packed]
usb_cdc_dmm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_DMM_TYPE, int8]
bcdVersion int16
wMaxCommand int16
} [packed]
usb_cdc_mdlm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_TYPE, int8]
bcdVersion int16
bGUID usb_cdc_ecm_mbm_guid
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L61
usb_cdc_ecm_mbm_guid {
id0 const[0x14f5e048ba817a3, int64]
id1 const[0x2a397ecbffc007a6, int64]
} [packed]
usb_cdc_mdlm_detail_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_DETAIL_TYPE, int8]
bGuidDescriptorType int8
bDetailData array[int8, 0:256]
} [packed]
usb_cdc_obex_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_OBEX_TYPE, int8]
bcdVersion int16
} [packed]
usb_cdc_ncm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NCM_TYPE, int8]
bcdNcmVersion int16
bmNetworkCapabilities flags[usb_cdc_ncm_ncaps, int8]
} [packed]
usb_cdc_ncm_ncaps = USB_CDC_NCM_NCAP_ETH_FILTER, USB_CDC_NCM_NCAP_NET_ADDRESS, USB_CDC_NCM_NCAP_ENCAP_COMMAND, USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE, USB_CDC_NCM_NCAP_CRC_MODE, USB_CDC_NCM_NCAP_NTB_INPUT_SIZE
usb_cdc_mbim_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_TYPE, int8]
bcdMBIMVersion int16
wMaxControlMessage int16
bNumberFilters int8
bMaxFilterSize int8
wMaxSegmentSize int16
bmNetworkCapabilities int8
} [packed]
usb_cdc_mbim_extended_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_EXTENDED_TYPE, int8]
bcdMBIMExtendedVersion int16
bMaxOutstandingCommandMessages int8
wMTU int16
} [packed]
vusb_descriptors_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
usb_cdc_ecm_mac {
# This is a UTF16 encoded string "424242424242".
data0 const[0x3400320034003200, int64be]
data1 const[0x3400320034003200, int64be]
data2 const[0x3400320034003200, int64be]
} [packed]
vusb_responses_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC NCM class specific descriptions.
# CDC NCM is based on CDC ECM, so some of the descriptions are reused.
# https://www.usb.org/document-library/network-control-model-devices-specification-v10-and-errata-and-adopters-agreement
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ncm.c
resource fd_usb_cdc_ncm[fd_usb]
syz_usb_connect$cdc_ncm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ncm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ncm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ncm(fd fd_usb_cdc_ncm, descs ptr[in, vusb_descriptors_cdc_ncm], resps ptr[in, vusb_responses_cdc_ncm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ncm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ncm, 1]]
} [packed]
usb_config_descriptor_cdc_ncm {
inner usb_config_descriptor_t[const[1, int8], const[2, int8], usb_interface_descriptors_cdc_ncm]
} [packed]
usb_interface_descriptors_cdc_ncm {
control usb_interface_descriptor_fixed_t[0, CDC_NCM_COMM_ALTSETTING_NCM, 1, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, usb_cdc_header_ncm, usb_endpoint_descriptor_cdc_ecm_notify]
data_nop usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, void]
data usb_interface_descriptor_fixed_t[1, CDC_NCM_DATA_ALTSETTING_NCM, 2, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, usb_endpoint_descriptors_cdc_ncm_data]
} [packed]
usb_endpoint_descriptors_cdc_ncm_data {
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ncm.c#L798
usb_cdc_header_ncm {
union usb_cdc_union_desc_t[0, 1]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
ncm usb_cdc_ncm_desc
other array[usb_cdc_header_ncm_other, 0:6]
} [packed]
usb_cdc_header_ncm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
vusb_descriptors_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
vusb_responses_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_CDC_GET_NTB_PARAMETERS ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_PARAMETERS, usb_cdc_ncm_ntb_parameters]]
USB_CDC_GET_NTB_INPUT_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_INPUT_SIZE, int32]]
USB_CDC_GET_NTB_FORMAT ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_FORMAT, int16[0:1]]]
USB_CDC_GET_MAX_DATAGRAM_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_MAX_DATAGRAM_SIZE, int16]]
USB_CDC_GET_CRC_MODE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_CRC_MODE, int16[0:1]]]
} [packed]
usb_cdc_ncm_ntb_parameters {
wLength int16
bmNtbFormatsSupported int16
dwNtbInMaxSize int32
wNdpInDivisor int16
wNdpInPayloadRemainder int16
wNdpInAlignment int16
wPadding1 int16
dwNtbOutMaxSize int32
wNdpOutDivisor int16
wNdpOutPayloadRemainder int16
wNdpOutAlignment int16
wNtbOutMaxDatagrams int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC1 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1_legacy.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
# TODO: find out which /dev/ files are created by connected UAC1 devices and add descriptions for those.
resource fd_usb_uac1[fd_usb]
syz_usb_connect$uac1(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac1], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac1 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac1(fd fd_usb_uac1, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac1 {
inner usb_device_descriptor_t[0, 0, 0, 0x1d6b, 0x101, 64, array[usb_config_descriptor_uac1, 1]]
} [packed]
usb_config_descriptor_uac1 {
inner usb_config_descriptor_t[const[1, int8], const[3, int8], usb_interface_descriptors_uac1]
} [packed]
# TODO: control interface might have and optional interrupt endpoint.
usb_interface_descriptors_uac1 {
inner usb_interface_descriptors_uac1_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac1_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, 0, uac_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC uses IDs to make it possible for terminals and units to refer to each other.
# We don't have a way to describe this, so just use a limited number of ids.
type uac_id int8[1:6]
uac_control_iface_extra_descriptors {
header uac1_ac_header_descriptor
others array[uac_control_iface_extra_descriptor, 0:6]
} [packed]
uac1_ac_header_descriptor {
bLength const[UAC_DT_AC_HEADER_LENGTH, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdADC int16
wTotalLength len[uac_control_iface_extra_descriptors, int16]
bInCollection const[F_AUDIO_NUM_INTERFACES, int8]
# These must match interfaces numbers.
baInterfaceNr0 const[1, int8]
baInterfaceNr1 const[2, int8]
} [packed]
uac_control_iface_extra_descriptor [
input_terminal uac_input_terminal_descriptor
output_terminal uac1_output_terminal_descriptor
mixer_unit uac_mixer_unit_descriptor
selector_unit uac_selector_unit_descriptor
feature_unit uac_feature_unit_descriptor
processing_unit uac_processing_unit_descriptor
extension_unit uac_extension_unit_descriptor
] [varlen]
define F_AUDIO_NUM_INTERFACES 2
define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
uac_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bNrChannels int8
wChannelConfig int16
iChannelNames int8
iTerminal int8
} [packed]
# The following list contains input terminal types and inout terminal types.
uac_input_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_INPUT_TERMINAL_UNDEFINED, UAC_INPUT_TERMINAL_MICROPHONE, UAC_INPUT_TERMINAL_DESKTOP_MICROPHONE, UAC_INPUT_TERMINAL_PERSONAL_MICROPHONE, UAC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE, UAC_INPUT_TERMINAL_MICROPHONE_ARRAY, UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
# The following list contains output terminal types and inout terminal types.
uac_output_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_OUTPUT_TERMINAL_UNDEFINED, UAC_OUTPUT_TERMINAL_SPEAKER, UAC_OUTPUT_TERMINAL_HEADPHONES, UAC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO, UAC_OUTPUT_TERMINAL_DESKTOP_SPEAKER, UAC_OUTPUT_TERMINAL_ROOM_SPEAKER, UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER, UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
uac1_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
iTerminal int8
} [packed]
uac_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_selector_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_SELECTOR_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bControlSize len[bmaControls, int8]
bmaControls array[flags[uac_feature_unit_controls, int16], 1:6]
iFeature int8
} [packed]
uac_feature_unit_controls = UAC_FU_MUTE, UAC_FU_VOLUME, UAC_FU_BASS, UAC_FU_MID, UAC_FU_TREBLE, UAC_FU_GRAPHIC_EQUALIZER, UAC_FU_AUTOMATIC_GAIN, UAC_FU_DELAY, UAC_FU_BASS_BOOST, UAC_FU_LOUDNESS
uac_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_PROCESSING_UNIT, int8]
bUnitID uac_id
wProcessType flags[uac_processing_unit_types, int16]
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_processing_unit_types = UAC_PROCESS_UNDEFINED, UAC_PROCESS_UP_DOWNMIX, UAC_PROCESS_DOLBY_PROLOGIC, UAC_PROCESS_STEREO_EXTENDER, UAC_PROCESS_REVERB, UAC_PROCESS_CHORUS, UAC_PROCESS_DYN_RANGE_COMP
uac_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_EXTENSION_UNIT, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_iface_extra_descriptors {
others array[uac_as_iface_extra_descriptor, 0:6]
} [packed]
uac_as_iface_extra_descriptor [
as_header uac1_as_header_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
format_type_i_ext uac_format_type_i_ext_descriptor
] [varlen]
uac1_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bDelay int8
wFormatTag flags[uac_format_tags, int16]
} [packed]
uac_format_tags = UAC_FORMAT_TYPE_I_UNDEFINED, UAC_FORMAT_TYPE_I_PCM, UAC_FORMAT_TYPE_I_PCM8, UAC_FORMAT_TYPE_I_IEEE_FLOAT, UAC_FORMAT_TYPE_I_ALAW, UAC_FORMAT_TYPE_I_MULAW, UAC_FORMAT_TYPE_II_MPEG, UAC_FORMAT_TYPE_II_AC3
uac_usb_format_types_i = UAC_FORMAT_TYPE_I, UAC_FORMAT_TYPE_II, UAC_FORMAT_TYPE_III, UAC_FORMAT_TYPE_UNDEFINED
uac_format_type_i_continuous_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tLowerSamFreq array[int8, 0:3]
tUpperSamFreq array[int8, 0:3]
} [packed]
uac_format_type_i_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
uac_format_type_ii_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
uac_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
define USB_ENDPOINT_UAC1_AS_OUT_ADDRESS (1 | USB_DIR_OUT)
define USB_ENDPOINT_UAC1_AS_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_UAC1_AS_ATTRIBUTES (USB_ENDPOINT_SYNC_ADAPTIVE | USB_ENDPOINT_XFER_ISOC)
uac_iso_ep_attributes = USB_ENDPOINT_SYNCTYPE, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC
uac_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC_EP_GENERAL, int8]
bmAttributes flags[uac_iso_ep_attributes, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
vusb_descriptors_uac1 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_uac1 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
audio_UAC_GET_CUR ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_CUR, array[int8, 1:3]]]
audio_UAC_GET_MIN ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MIN, array[int8, 1:3]]]
audio_UAC_GET_MAX ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MAX, array[int8, 1:3]]]
audio_UAC_GET_RES ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_RES, array[int8, 1:4]]]
audio_UAC_GET_MEM ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MEM, array[int8, 3]]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC2 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac2.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac2[fd_usb]
syz_usb_connect$uac2(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac2], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac2 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac2(fd fd_usb_uac2, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac2 {
inner usb_device_descriptor_t[0, 0, 0, 0x41e, 0x3000, 64, array[usb_config_descriptor_uac2, 1]]
} [packed]
usb_config_descriptor_uac2 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac2_interface_assoc_descriptor, usb_interface_descriptors_uac2]
} [packed]
uac2_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[audio_function_category_types, int8]
bFunctionProtocol const[UAC_VERSION_2, int8]
iFunction int8
} [packed]
audio_function_category_types = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER
usb_interface_descriptors_uac2 {
inner usb_interface_descriptors_uac2_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac2_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_2, uac2_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptors {
header uac2_ac_header_descriptor
others array[uac2_control_iface_extra_descriptor, 0:6]
} [packed]
uac2_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bcdADC int16
bCategory flags[uac2_feature_unit_controls, int8]
wTotalLength len[uac2_control_iface_extra_descriptors, int16]
bmControls int8
} [packed]
uac2_feature_unit_controls = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER, uac_feature_unit_controls
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_as_iface_extra_descriptors {
others array[uac2_as_iface_extra_descriptor, 0:6]
} [packed]
uac2_as_iface_extra_descriptor [
as_header uac2_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
uac2_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int8
bFormatType flags[uac_usb_format_types_i, int8]
bmFormats flags[uac_format_tags, int32]
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
} [packed]
b_sub_slot_sizes = 1, 2, 3, 4
uac2_format_type_i_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize flags[b_sub_slot_sizes, int8]
bBitResolution int8
} [packed]
uac2_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac_format_type_ii_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bHeaderLength int8
bSideBandProtocol int8
} [packed]
uac_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac2_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubtype const[UAC_EP_GENERAL, int8]
bmAttributes flags[csep_bm_attributes, int8]
bmControls flags[csep_bm_controls, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
csep_bm_attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, UAC_EP_CS_ATTR_PITCH_CONTROL, UAC_EP_CS_ATTR_FILL_MAX
csep_bm_controls = UAC2_CONTROL_PITCH, UAC2_CONTROL_DATA_OVERRUN, UAC2_CONTROL_DATA_UNDERRUN
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptor [
input_terminal uac2_input_terminal_descriptor
output_terminal uac2_output_terminal_descriptor
mixer_unit uac2_mixer_unit_descriptor
selector_unit uac2_clock_selector_descriptor
feature_unit uac2_feature_unit_descriptor
processing_unit uac2_processing_unit_descriptor
extension_unit uac2_extension_unit_descriptor
effect_unit uac2_effect_unit_descriptor
sample_rate uac2_sample_rate_descriptor
source_unit uac2_clock_source_descriptor
multiply_unit uac2_clock_multiplier_descriptor
] [varlen]
uac2_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
bmControls int8
iTerminal int8
} [packed]
uac2_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal int8
bSourceID uac_id
bCSourceID int8
bmControls int16
iTerminal int8
} [packed]
uac2_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Figure out if bmControls and iClockSelector should be a part of this structure.
uac2_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
# TODO: Verify coverage.
uac2_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_PROCESSING_UNIT_V2, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_processing_unit_types = UAC2_PROCESS_UNDEFINED, UAC2_PROCESS_UP_DOWNMIX, UAC2_PROCESS_DOLBY_PROLOCIC, UAC2_PROCESS_STEREO_EXTENDER
uac2_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_EXTENSION_UNIT_V2, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Verify coverage.
uac2_effect_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_EFFECT_UNIT, int8]
bUnitID uac_id
wEffectType flags[uac2_effect_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_effect_unit_types = UAC2_EFFECT_UNDEFINED, UAC2_EFFECT_PARAM_EQ, UAC2_EFFECT_REVERB, UAC2_EFFECT_MOD_DELAY, UAC2_EFFECT_DYN_RANGE_COMP
uac2_sample_rate_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_SAMPLE_RATE_CONVERTER, int8]
bUnitID uac_id
wProcessType flags[uac2_processing_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_feature_unit_controls, int16], 1:6]
} [packed]
uac2_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac2_clock_bmattribute_types, int8]
bmControls int8
bAssocTerminal int8
iClockSource flags[uac2_clock_source_types, int8]
} [packed]
uac2_clock_bmattribute_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_source_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int8
iClockMultiplier int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC3 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac3.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac3[fd_usb]
syz_usb_connect$uac3(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac3], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac3 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac3(fd fd_usb_uac3, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac3 {
inner usb_device_descriptor_t[0, 0, 0, 0x582, 0x582, 64, array[usb_config_descriptor_uac3, 1]]
} [packed]
usb_config_descriptor_uac3 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac3_interface_assoc_descriptor, usb_interface_descriptors_uac3]
} [packed]
uac3_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[uac3_all_subclasses, int8]
bFunctionProtocol const[UAC_VERSION_3, int8]
iFunction int8
} [packed]
usb_interface_descriptors_uac3 {
inner usb_interface_descriptors_uac3_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac3_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_3, uac3_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptors {
header uac3_ac_header_descriptor
others array[uac3_control_iface_extra_descriptor, 0:6]
} [packed]
uac3_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bCategory flags[uac3_feature_unit_controls, int8]
wTotalLength len[uac3_control_iface_extra_descriptors, int16]
bmControls int32
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_as_iface_extra_descriptors {
others array[uac3_as_iface_extra_descriptor, 0:6]
} [packed]
uac3_as_iface_extra_descriptor [
as_header uac3_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
# TODO: Figure out how wClusterDescrID is used in the kernel.
uac3_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int32
wClusterDescrID int16
bmFormats flags[uac_format_tags, int64]
bSubslotSize int8
bBitResolution int8
bmAuxProtocols int16
bControlSize int8
} [packed]
uac3_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC3_CS_ENDPOINT, int8]
bmControls int32
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptor [
input_terminal uac3_input_terminal_descriptor
output_terminal uac3_output_terminal_descriptor
mixer_unit uac3_mixer_unit_descriptor
selector_unit uac3_clock_selector_descriptor
source_unit uac3_clock_source_descriptor
multiply_unit uac3_clock_multiplier_descriptor
feature_unit uac3_feature_unit_descriptor
processing_unit uac3_processing_unit_descriptor
extension_unit uac3_extension_unit_descriptor
power_domain uac3_power_domain_descriptor
cluster_info_segment uac3_cluster_information_segment_descriptor
# Only cluster information segment is currently used in the kernel.See: sound/usb/stream.c
# cluster_segment uac3_cluster_segment_descriptor
# cluster_end_segment uac3_cluster_end_segment_descriptor
# The following units are not yet supported by the kernel.
# See audio_validators[] in sound/usb/validate.c:
# effect_unit uac3_effect_unit_descriptor
# sample_rate uac3_sample_rate_descriptor
# connectors_unit uac3_connectors_unit_descriptor
# extended_term_unit uac3_extended_terminal_unit
] [varlen]
uac3_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bmControls int32
wClusterDescrID int16
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
bCSourceID int8
bmControls int32
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac3_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
uac3_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac3_clock_bmattribute_types, int8]
bmControls int32
bReferenceTerminal int8
wClockSourceStr int16
} [packed]
uac3_clock_bmattribute_types = UAC3_CLOCK_SOURCE_TYPE_EXT, UAC3_CLOCK_SOURCE_TYPE_INT, UAC3_CLOCK_SOURCE_ASYNC, UAC3_CLOCK_SOURCE_SYNCED_TO_SOF
uac3_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int32
wCMultiplierDescrStr int16
} [packed]
uac3_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_feature_unit_controls, int32], 1:6]
} [packed]
uac3_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_PROCESSING_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_processing_unit_types = UAC3_PROCESS_UNDEFINED, UAC3_PROCESS_UP_DOWNMIX, UAC3_PROCESS_STEREO_EXTENDER, UAC3_PROCESS_MULTI_FUNCTION
uac3_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_EXTENSION_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_power_domain_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_POWER_DOMAIN, int8]
bPowerDomainID int8
waRecoveryTime1 int16
waRecoveryTime2 int16
bNrEntities int8
baEntityID array[int8, 0:8]
} [packed]
uac3_cluster_information_segment_descriptor {
bLength len[parent, int16]
bSegmentType const[UAC3_CHANNEL_INFORMATION, int8]
bChPurpose flags[uac3_cluster_channel_purposes, int8]
bChRelationship flags[uac3_cluster_channel_relationships, int8]
bChGroupID int8
} [packed]
uac3_cluster_channel_purposes = UAC3_PURPOSE_UNDEFINED, UAC3_PURPOSE_GENERIC_AUDIO, UAC3_PURPOSE_VOICE, UAC3_PURPOSE_SPEECH, UAC3_PURPOSE_AMBIENT, UAC3_PURPOSE_REFERENCE, UAC3_PURPOSE_ULTRASONIC, UAC3_PURPOSE_VIBROKINETIC, UAC3_PURPOSE_NON_AUDIO
uac3_cluster_channel_relationships = UAC3_CH_RELATIONSHIP_UNDEFINED, UAC3_CH_MONO, UAC3_CH_LEFT, UAC3_CH_RIGHT, UAC3_CH_ARRAY, UAC3_CH_PATTERN_X, UAC3_CH_PATTERN_Y, UAC3_CH_PATTERN_A, UAC3_CH_PATTERN_B, UAC3_CH_PATTERN_M, UAC3_CH_PATTERN_S, UAC3_CH_FRONT_LEFT, UAC3_CH_FRONT_RIGHT, UAC3_CH_FRONT_CENTER, UAC3_CH_FRONT_LEFT_OF_CENTER, UAC3_CH_FRONT_RIGHT_OF_CENTER, UAC3_CH_FRONT_WIDE_LEFT, UAC3_CH_FRONT_WIDE_RIGHT, UAC3_CH_SIDE_LEFT, UAC3_CH_SIDE_RIGHT, UAC3_CH_SURROUND_ARRAY_LEFT, UAC3_CH_SURROUND_ARRAY_RIGHT, UAC3_CH_BACK_LEFT, UAC3_CH_BACK_RIGHT, UAC3_CH_BACK_CENTER, UAC3_CH_BACK_LEFT_OF_CENTER, UAC3_CH_BACK_RIGHT_OF_CENTER, UAC3_CH_BACK_WIDE_LEFT, UAC3_CH_BACK_WIDE_RIGHT, UAC3_CH_TOP_CENTER, UAC3_CH_TOP_FRONT_LEFT, UAC3_CH_TOP_FRONT_RIGHT, UAC3_CH_TOP_FRONT_CENTER, UAC3_CH_TOP_FRONT_LOC, UAC3_CH_TOP_FRONT_ROC, UAC3_CH_TOP_FRONT_WIDE_LEFT, UAC3_CH_TOP_FRONT_WIDE_RIGHT, UAC3_CH_TOP_SIDE_LEFT, UAC3_CH_TOP_SIDE_RIGHT, UAC3_CH_TOP_SURR_ARRAY_LEFT, UAC3_CH_TOP_SURR_ARRAY_RIGHT, UAC3_CH_TOP_BACK_LEFT, UAC3_CH_TOP_BACK_RIGHT, UAC3_CH_TOP_BACK_CENTER, UAC3_CH_TOP_BACK_LOC, UAC3_CH_TOP_BACK_ROC, UAC3_CH_TOP_BACK_WIDE_LEFT, UAC3_CH_TOP_BACK_WIDE_RIGHT, UAC3_CH_BOTTOM_CENTER, UAC3_CH_BOTTOM_FRONT_LEFT, UAC3_CH_BOTTOM_FRONT_RIGHT, UAC3_CH_BOTTOM_FRONT_CENTER, UAC3_CH_BOTTOM_FRONT_LOC, UAC3_CH_BOTTOM_FRONT_ROC, UAC3_CH_BOTTOM_FRONT_WIDE_LEFT, UAC3_CH_BOTTOM_FRONT_WIDE_RIGHT, UAC3_CH_BOTTOM_SIDE_LEFT, UAC3_CH_BOTTOM_SIDE_RIGHT, UAC3_CH_BOTTOM_SURR_ARRAY_LEFT, UAC3_CH_BOTTOM_SURR_ARRAY_RIGHT, UAC3_CH_BOTTOM_BACK_LEFT, UAC3_CH_BOTTOM_BACK_RIGHT, UAC3_CH_BOTTOM_BACK_CENTER, UAC3_CH_BOTTOM_BACK_LOC, UAC3_CH_BOTTOM_BACK_ROC, UAC3_CH_BOTTOM_BACK_WIDE_LEFT, UAC3_CH_BOTTOM_BACK_WIDE_RIGHT, UAC3_CH_LOW_FREQUENCY_EFFECTS, UAC3_CH_LFE_LEFT, UAC3_CH_LFE_RIGHT, UAC3_CH_HEADPHONE_LEFT, UAC3_CH_HEADPHONE_RIGHT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# This list consists of uac3_func_subclasses + uac3_badd_classes.
uac3_all_subclasses = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0, UAC3_FUNCTION_SUBCLASS_GENERIC_IO, UAC3_FUNCTION_SUBCLASS_HEADPHONE, UAC3_FUNCTION_SUBCLASS_SPEAKER, UAC3_FUNCTION_SUBCLASS_MICROPHONE, UAC3_FUNCTION_SUBCLASS_HEADSET, UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE
uac3_feature_unit_controls = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_DESKTOP_SPEAKER, UAC3_FUNCTION_HOME_THEATER, UAC3_FUNCTION_MICROPHONE, UAC3_FUNCTION_HEADSET, UAC3_FUNCTION_TELEPHONE, UAC3_FUNCTION_CONVERTER, UAC3_FUNCTION_SOUND_RECORDER, UAC3_FUNCTION_IO_BOX, UAC3_FUNCTION_MUSICAL_INSTRUMENT, UAC3_FUNCTION_PRO_AUDIO, UAC3_FUNCTION_AUDIO_VIDEO, UAC3_FUNCTION_CONTROL_PANEL, UAC3_FUNCTION_HEADPHONE, UAC3_FUNCTION_GENERIC_SPEAKER, UAC3_FUNCTION_HEADSET_ADAPTER, UAC3_FUNCTION_SPEAKERPHONE, UAC3_FUNCTION_OTHER
# TODO: Support uac3 badd profiles. See sound/usb/mixer.c: snd_usb_mixer_controls_badd()
# uac3_badd_endpoint_descriptor {
# inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
# } [packed]
#uac3_badd_maxsizes = UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# MIDI device class specific descriptions.
# https://www.usb.org/sites/default/files/midi10.pdf
# https://elixir.bootlin.com/linux/latest/source/sound/usb/midi.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_midi.c
syz_usb_connect$midi(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_midi], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
usb_device_descriptor_midi {
inner usb_device_descriptor_t[0, 0, 0, 0x1430, 0x474b, 64, array[usb_config_descriptor_midi, 1]]
} [packed]
usb_config_descriptor_midi {
inner usb_config_descriptor_t[const[1, int8], const[1, int8], usb_interface_descriptors_midi]
} [packed]
usb_interface_descriptors_midi {
inner usb_interface_descriptors_midi_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_midi_inner {
control usb_interface_descriptor_eps_array_t[const[0, int8], const[0, int8], const[USB_CLASS_AUDIO, int8], const[USB_SUBCLASS_MIDISTREAMING, int8], flags[uac_version_types, int8], array[usb_midi_iface_extra], array[usb_endpoint_descriptor_midi, 0:8]]
} [packed]
usb_endpoint_descriptor_midi {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], usb_ms_endpoint_descriptor]
} [packed]
midi_jack_type = USB_MS_EMBEDDED, USB_MS_EXTERNAL
uac_version_types = UAC_VERSION_1, UAC_VERSION_2, UAC_VERSION_3
usb_ms_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[USB_MS_GENERAL, int8]
bNumEmbMIDIJack len[baAssocJackID, int8]
baAssocJackID array[int8, 0:16]
} [packed]
usb_midi_iface_extra [
ms_header usb_ms_header_descriptor
midi_in_jack usb_midi_in_jack_descriptor
midi_out_jack usb_midi_out_jack_descriptor
] [varlen]
usb_ms_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdMSC int16
wTotalLength len[parent, int16]
} [packed]
usb_midi_in_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_IN_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
iJack int8
} [packed]
usb_midi_out_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_OUT_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
bNrInputPins len[pins, int8]
pins array[usb_midi_source_pin]
iJack int8
} [packed]
usb_midi_source_pin {
baSourceID int8
baSourcePin int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# ath9k driver specific descriptions.
include <drivers/net/wireless/ath/ath9k/htc_hst.h>
include <drivers/net/wireless/ath/ath9k/hif_usb.h>
define USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS (1)
define USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_IN_ADDRESS (3 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS (4)
define USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS (5)
define USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS (6)
resource fd_usb_ath9k[fd_usb]
syz_usb_connect_ath9k(speed const[USB_SPEED_HIGH], dev_len len[dev], dev ptr[in, usb_device_descriptor_ath9k], conn_descs const[0]) fd_usb_ath9k (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_ep_write$ath9k_ep1(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS], len bytesize[data], data ptr[in, ath9k_bulk_frame]) (timeout[300], remote_cover)
syz_usb_ep_write$ath9k_ep2(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS], len bytesize[data], data ptr[in, htc_frame]) (timeout[300], remote_cover)
usb_device_descriptor_ath9k {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xcf3, 0x9271, 0x108, array[usb_config_descriptor_ath9k, 1]]
} [packed]
usb_config_descriptor_ath9k {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_ath9k]
} [packed]
usb_interface_descriptor_ath9k {
iface usb_interface_descriptor_fixed_t[0, 0, 6, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_ath9k]
} [packed]
usb_endpoint_descriptors_ath9k {
bulk_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
int_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
bulk_extra1 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_extra2 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
} [packed]
define USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_ATH9K_INT_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
ath9k_bulk_frame {
packets array[ath9k_bulk_packet]
} [packed]
ath9k_bulk_packet {
pkt_len len[data, int16]
pkt_tag const[ATH_USB_RX_STREAM_MODE_TAG, int16]
data array[int8]
} [packed, align[4]]
htc_frame [
ready htc_ready_frame
conn_svc_rsp htc_conn_svc_rsp_frame
generic htc_generic_frame
] [varlen]
# This is actually wrong, as the driver is buggy and doesn't skip the header
# before processing the frame payload, but let's leave it like thise for now.
htc_ready_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_ready_msg
} [packed]
htc_ready_msg {
message_id const[HTC_MSG_READY_ID, int16be]
credits int16be
credit_size int16be
max_endpoints int8
pad int8
} [packed]
htc_conn_svc_rsp_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_conn_svc_rspmsg
} [packed]
htc_conn_svc_rspmsg {
message_id const[HTC_MSG_CONNECT_SERVICE_RESPONSE_ID, int16be]
service_id flags[htc_svcs, int16be]
status const[HTC_SERVICE_SUCCESS, int8]
endpoint_id int8
max_msg_len int16be
svc_meta_len int8
pad int8
} [packed]
htc_svcs = HTC_CTRL_RSVD_SVC, HTC_LOOPBACK_RSVD_SVC, WMI_CONTROL_SVC, WMI_BEACON_SVC, WMI_CAB_SVC, WMI_UAPSD_SVC, WMI_MGMT_SVC, WMI_DATA_VO_SVC, WMI_DATA_VI_SVC, WMI_DATA_BE_SVC, WMI_DATA_BE_SVC
htc_generic_frame {
endpoint_id int8[0:8]
flags flags[htc_frame_flags, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload array[int8, 0:256]
} [packed]
htc_frame_flags = HTC_FLAGS_RECV_TRAILER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Assorted driver-specific descriptions of generic syz_* calls' variants.
# Generic calls such as syz_usb_connect() and syz_usb_control_io() should be enough
# (in theory) to emulate a proper device and finish driver probes without a hitch.
# However, there are cases when syzkaller fails to come up with correct inputs to achieve it.
# Use fixed descriptors to quickly pass through probe() to access select drivers' post-probe functionality.
# It is important to note that, one way or another, drivers in question require multiple control requests
# between a driver and a device processed during probe(). Descriptions below do not deal with specific
# CTRL requests as such (except for basic information included in vusb_responses_XXX). Instead, rely on
# seeds, created both manually and with syzkaller's help. For examples, see sys/linux/test/vusb_XXX.
# Common constants for endpoint descriptors.
define USB_ENDPOINT_BULK_ATTR (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_INT_ATTR (USB_ENDPOINT_XFER_INT)
define USB_FIXED_ENDPOINT_BULK_IN_ADDR (1 | USB_DIR_IN)
define USB_FIXED_ENDPOINT_BULK_OUT_ADDR (2)
define USB_FIXED_ENDPOINT_INT_IN_ADDR (3 | USB_DIR_IN)
define USB_RECIP_DEVICE 0x00
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# rtl8150 driver specific descriptions.
resource fd_usb_rtl8150[fd_usb]
syz_usb_connect$rtl8150(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_rtl8150], conn_descs const[0]) fd_usb_rtl8150 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$rtl8150(fd fd_usb_rtl8150, descs ptr[in, vusb_descriptors_rtl8150], resps ptr[in, vusb_responses_rtl8150]) (timeout[300], remote_cover)
usb_device_descriptor_rtl8150 {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xbda, 0x8150, 0, array[usb_config_descriptor_rtl8150, 1]]
} [packed]
usb_config_descriptor_rtl8150 {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_rtl8150]
} [packed]
usb_interface_descriptor_rtl8150 {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_rtl8150]
} [packed]
usb_endpoint_descriptors_rtl8150 {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
RTL8150_REQ_GET_REGS ptr[in, vusb_response_t[RTL8150_REQT_READ, RTL8150_REQ_GET_REGS, array[int8, 0:6]]]
RTL8150_REQ_SET_REGS ptr[in, vusb_response_t[RTL8150_REQT_WRITE, RTL8150_REQ_SET_REGS, array[int8, 0:6]]]
} [packed]
define RTL8150_REQ_GET_REGS 0x05
define RTL8150_REQ_SET_REGS 0x05
define RTL8150_REQT_READ 0xc0
define RTL8150_REQT_WRITE 0x40
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# sierra_net driver specific descriptions.
resource fd_usb_sierra_net[fd_usb]
syz_usb_connect$sierra_net(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_sierra_net], conn_descs const[0]) fd_usb_sierra_net (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$sierra_net(fd fd_usb_sierra_net, descs ptr[in, vusb_descriptors_sierra_net], resps ptr[in, vusb_responses_sierra_net]) (timeout[300], remote_cover)
usb_device_descriptor_sierra_net {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x1199, 0x68a3, 0, array[usb_config_descriptor_sierra_net, 1]]
} [packed]
usb_config_descriptor_sierra_net {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_sierra_net]
} [packed]
usb_interface_descriptor_sierra_net {
iface usb_interface_descriptor_fixed_t[7, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_sierra_net]
} [packed]
# sierra_net driver does not expect fixed ep addresses, so refrain from being too specific here.
# As long as we ensure there are 3 endpoints, 2 bulk and 1 int, syzkaller should figure it out.
usb_endpoint_descriptors_sierra_net {
bulk_in usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
bulk_out usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
status usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_INT_ATTR, int8], void]
} [packed]
vusb_descriptors_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_CDC_GET_ENCAPSULATED_RESPONSE ptr[in, vusb_response_t[SIERRA_CMD_TYPE_IN, USB_CDC_GET_ENCAPSULATED_RESPONSE, array[int8, 1024]]]
USB_CDC_SEND_ENCAPSULATED_COMMANDT ptr[in, vusb_response_t[SIERRA_CMD_TYPE_OUT, USB_CDC_SEND_ENCAPSULATED_COMMAND, array[int8, 0:4]]]
} [packed]
define SIERRA_CMD_TYPE_IN (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
define SIERRA_CMD_TYPE_OUT (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# lan78xx driver specific descriptions.
# While these syz_* variants noticably help with the probe() process, they are not enough.
# This is due to a high number of control requests expected between the driver and the device.
include <drivers/net/usb/smsc95xx.h>
resource fd_usb_lan78xx[fd_usb]
syz_usb_connect$lan78xx(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_lan78xx], conn_descs const[0]) fd_usb_lan78xx (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$lan78xx(fd fd_usb_lan78xx, descs ptr[in, vusb_descriptors_lan78xx], resps ptr[in, vusb_responses_lan78xx]) (timeout[300], remote_cover)
usb_device_descriptor_lan78xx {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x424, 0x7850, 0, array[usb_config_descriptor_lan78xx, 1]]
} [packed]
usb_config_descriptor_lan78xx {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_lan78xx]
} [packed]
usb_interface_descriptor_lan78xx {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_lan78xx]
} [packed]
usb_endpoint_descriptors_lan78xx {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_VENDOR_REQUEST_READ_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_READ_REGISTER, int32]]
USB_VENDOR_REQUEST_WRITE_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_OUT, USB_VENDOR_REQUEST_WRITE_REGISTER, int32]]
USB_VENDOR_REQUEST_GET_STATS ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_GET_STATS, array[int8, 47]]]
} [packed]
define LAN78XX_REG_TYPE_IN (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
define LAN78XX_REG_TYPE_OUT (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
]
|
| 112/2 |
2026/07/30 12:29 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 83035
output: 1292
thoughts: 2179
Thoughts: **Navigating the `syz_usb_connect` Challenge**
Okay, so I'm trying to work with `syz_usb_connect`, and the first thing that jumps out is the `dev ptr[in, usb_device_descriptor]` argument. Right, it's a struct, not just a string, so I can't simply pass in raw bytes as I initially thought. But wait, checking the vusb.txt definition, I see this third argument is indeed a `usb_device_descriptor`, confirming that it needs a structured input, not just a bare string literal like `&AUTO="\x12\x01..."`.
So, I need to figure out how to give this pseudo-syscall the structure it expects. Using `&AUTO=""` doesn't work directly because of the type mismatch. And `&AUTO=""/43` doesn't seem right either. The best approach is clearly to construct the struct using `&AUTO={...}`. The tricky part is the manual construction of the complex `usb_device_descriptor` struct.
While `syz_usb_connect` is pseudo-syscall, I can see the advantage of pre-populating memory. So, could I just use `syz_usb_connect(3, 0x2b, &(0x7f0000000000)="", 0)`? No, that still presents it as a string. Syzkaller needs raw bytes for the struct. But is it even possible to just write bytes directly to a memory location and then pass a pointer? Can I just use `&AUTO={{0x12, 0x1, 0x200, 0, 0, 0, 0x40, 0x2040, 0x7200, 0, 1, 2, 3, 1, ...}}`? But this seems so cumbersome.
Okay, let's explore if I can just write raw bytes somewhere in memory and then pass a pointer to `syz_usb_connect`. I can't directly use a `memcpy` in syzkaller. But can I use write syscall for that purpose? I could try: `write(-1, &(0x7f0000000000)="1201...", 43)`.
However, the problem is that when I call syz_usb_connect, if I just pass a pointer, `syzkaller` will try to fill the `usb_device_descriptor` struct at that address, overwriting my carefully crafted bytes! So I need some way to tell `syzkaller` to just use the bytes at the location, not initialize it with default values.
Aha! `syzkaller` initializes memory for pointers before the program runs. So, if I use `&(0x7f0000000000)={...}`, it will initialize. And maybe if I use `&(0x7f0000000000)=ANY` it will work? But `ANY` is only for `ptr[in, ANY]`. Ah, but I can use a hex string to give `syzkaller` my raw bytes! Based on the documentation `pointer-arg = "&" pointer-arg-addr ["=ANY"] "=" arg` and `arg` can be a hex string. So: `&(0x7f0000000000)=ANY="1201000200000040402000720000010203010902190001010080fa0904000001ff00000007058102000200"`. Let's test that!
|
| 113/2 |
2026/07/30 12:29 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0x2b, &(0x7f0000000000)=ANY="1201000200000040402000720000010203010902190001010080fa0904000001ff00000007058102000200", 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r7 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r8 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r9 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r10 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r11 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r12 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r13 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r14 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r15 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r16 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r17 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r18 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r9, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r10, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r11, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r12, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r15, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r16, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r17, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r18, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 114/2 |
2026/07/30 12:29 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 87516
output: 40
thoughts: 151
Thoughts: **Debugging a String Argument for syz_usb_connect**
Okay, here we go again, encountering this pesky "`wrong string arg`" error. I need to figure out what's causing this. Let's start by double-checking the documentation for `ANY`. Right, it shows `pointer-arg = "&" pointer-arg-addr ["=ANY"] "=" arg`. I remember now, if the argument, `arg`, is a string, then it should be formatted as `&AUTO=ANY="..."`. But hang on, `syz_usb_connect` takes `dev ptr[in, usb_device_descriptor]`. Does using `ANY` mean it's expecting a hex string? I'm pretty sure that's how it works.
I should probably confirm that with some examples. The best approach is to check how `syz_usb_connect` is currently used in the syzkaller tests themselves. I'll fire up `git log` and search for usages of `syz_usb_connect` within the `sys/linux/test/` directory. That'll give me some real-world examples to see how this function is correctly invoked and what its arguments should look like. That'll give me the best clue to solve this issue.
|
| 115/2 |
2026/07/30 12:29 |
tool |
git-log |
0m
Args: map[CodeRegexp:syz_usb_connect Count:10 PathPrefix:sys/linux/test/]
Results:
|
| 116/2 |
2026/07/30 12:29 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 87990
output: 1461
thoughts: 3637
Thoughts: **Constructing a USB Device Descriptor in Syzkaller**
Okay, first things first, I need to remember that the `sys/linux/test/` directory isn't in the kernel tree, it's actually in the syzkaller tree. And since I don't have direct access to that syzkaller tree, I'll have to build this descriptor from scratch. Good, I can do this. I've got a grasp of the `usb_device_descriptor` structure. I need to make sure the nested structures, especially `usb_config_descriptor`, `usb_interface_descriptor` and `usb_endpoint_descriptor` are correct.
Let's break it down. I've reconstructed the `usb_device_descriptor` from its definitions. Now, I need to build the struct literal. I see how the descriptors chain together. There is the initial `usb_device_descriptor`, which contains `usb_config_descriptor`. The `usb_config_descriptor` contains `usb_interface_descriptor` and the `usb_interface_descriptor` contains `usb_endpoint_descriptor`. I've got the hierarchy laid out.
I need to handle `void` fields in `usb_config_descriptor`. Ah, right, in syzkaller, `void` fields are omitted from struct literals, so I won't need to specify anything there. The `extra` field of the other descriptors is defined as array, and the array can be empty, which is how I need to treat it.
Okay, let's try using `AUTO` for the `const` and `len` fields. The problem is, `idVendor` and `idProduct` are defined as `const`. My initial struct construct will probably set them to something different from what I want. They might get overwritten by syzkaller's patching, so I can try leaving them, but I need a way to ensure these values are what I need.
And then I read the comment. `idVendor` and `idProduct` are actually patched by the Go code in `sys/linux/init_vusb.go`. Alright, so syzkaller *does* patch them, which means trying to set them directly via the struct definition isn't the best way. I should be able to force it by using `ANY`. I remember that if I use `ANY`, I can pass raw bytes to the program. Let me try it.
|
| 117/2 |
2026/07/30 12:30 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0x2b, &(0x7f0000000000)=ANY=[0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x40, 0x20, 0x00, 0x72, 0x00, 0x00, 0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0xfa, 0x09, 0x04, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00], 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r7 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r8 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r9 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r10 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r11 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r12 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
r13 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r14 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r15 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r16 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r17 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r18 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r9, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r10, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r11, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r12, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r15, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r16, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r17, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r18, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 118/2 |
2026/07/30 12:30 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 93934
output: 20
thoughts: 1628
Thoughts: **Navigating the USB and I2C Labyrinth**
Okay, so I'm trying to figure out how to trigger this bug, and it's sending me down a rabbit hole. I initially thought this had something to do with the `ANY` type, trying to feed it a union or struct. But after looking at the "wrong string arg" error, I think the `ANY` type expects a struct. I tried to use a struct literal, but I am not certain if it is the correct one.
I then started to focus on the `au0828` USB device and `syz_usb_connect`. I quickly realized that while I could use `&AUTO=""` for auto-populating the struct, there are `const` fields that syzkaller will reject unless they are zero or `AUTO`. The Go code *does* patch these fields, but I need to figure out how syzkaller knows which vendor/product IDs to use, because if they are not the same, I am not emulating the correct USB device. I see that syzkaller randomly patches them to known USB IDs. And if `au0828` isn't in that list, I'm out of luck. This also means I cannot easily use `syz_usb_connect` to trigger the bug. I also see that there are different variants of this system call, but none that look like they specifically target `au0828`.
So, if I can't directly emulate the device with `syz_usb_connect`, how was the bug triggered? The crash report points to `nsim_dev_trap_skb_build` which belongs to `netdevsim` and then a UAF in `i2c_adapter_lock_bus`. I remember that the error message shows the buggy object is `kmalloc-4k`. That makes me think a `struct usb_device` *could* be the problem because it's roughly 2251 bytes, which would fit in `kmalloc-4k`.
But wait, this could be something else entirely! If the crash is in `i2c_adapter_lock_bus`, which is called from `i2c_smbus_xfer`, and the UAF is on `adapter->dev.parent`, I have to figure out what driver registers an I2C adapter with `dev.parent` pointing to a `kmalloc-4k` object. `netdevsim` *allocates* a `kmalloc-4k` object, but it does *not* register I2C adapters. So, this looks like a reallocation scenario. The original object was freed, then `netdevsim` allocated an `skb` in the same `kmalloc-4k` slot and freed it. That means the original object was freed *before* `netdevsim` came into play.
If the original object was a `kmalloc-4k` object, it *could* be a `struct usb_device`, but it could be something else. What other drivers use I2C and could have a `kmalloc-4k` object as `parent`? Could it be a `struct net_device`? `net_device` is allocated via `alloc_netdev`, which uses `kvmalloc`, which often ends up in `kmalloc-4k`. Aha! Are there any network drivers that register I2C adapters? It makes me think SFP modules or PHYs.
I have to wonder if a network device registers an I2C adapter, and then the netdev is unregistered and freed, but the I2C adapter is *not* unregistered. I'll have to investigate if any network drivers register I2C adapters. I'll need to check the code, maybe in `drivers/net/ethernet/mellanox/mlx5/core/en_main.c` or in `drivers/net/usb/`. Is it a `struct usb_interface`, `struct v4l2_device`, `struct i2c_client`, or `struct platform_device`? I'll search for `i2c_add_adapter` or `i2c_add_numbered_adapter` where `dev.parent` is set to figure this out.
|
| 119/2 |
2026/07/30 12:30 |
tool |
grepper |
0m
Args: map[Expression:adapter\.dev\.parent =]
Results: map[Output:drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c=160=struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
--
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c-176- i2c->adapter.owner = THIS_MODULE;
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c:177: i2c->adapter.dev.parent = dev->dev;
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c-178- i2c->dev = dev;
--
drivers/gpu/drm/gma500/cdv_intel_dp.c=845=cdv_intel_dp_i2c_init(struct gma_connector *connector,
--
drivers/gpu/drm/gma500/cdv_intel_dp.c-860- intel_dp->adapter.algo_data = &intel_dp->algo;
drivers/gpu/drm/gma500/cdv_intel_dp.c:861: intel_dp->adapter.dev.parent = connector->base.kdev;
drivers/gpu/drm/gma500/cdv_intel_dp.c-862-
--
drivers/gpu/drm/gma500/intel_gmbus.c=173=intel_gpio_create(struct drm_psb_private *dev_priv, u32 pin)
--
drivers/gpu/drm/gma500/intel_gmbus.c-200- gpio->adapter.algo_data = &gpio->algo;
drivers/gpu/drm/gma500/intel_gmbus.c:201: gpio->adapter.dev.parent = dev_priv->dev.dev;
drivers/gpu/drm/gma500/intel_gmbus.c-202- gpio->algo.setsda = set_data;
--
drivers/gpu/drm/gma500/intel_gmbus.c=387=int gma_intel_setup_gmbus(struct drm_device *dev)
--
drivers/gpu/drm/gma500/intel_gmbus.c-419-
drivers/gpu/drm/gma500/intel_gmbus.c:420: bus->adapter.dev.parent = dev->dev;
drivers/gpu/drm/gma500/intel_gmbus.c-421- bus->adapter.algo_data = dev_priv;
--
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c=80=int hibmc_ddc_create(struct drm_device *drm_dev, struct hibmc_vdac *vdac)
--
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c-83- snprintf(vdac->adapter.name, I2C_NAME_SIZE, "HIS i2c bit bus");
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c:84: vdac->adapter.dev.parent = drm_dev->dev;
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c-85- i2c_set_adapdata(&vdac->adapter, vdac);
--
drivers/gpu/drm/i915/display/intel_gmbus.c=903=int intel_gmbus_setup(struct intel_display *display)
--
drivers/gpu/drm/i915/display/intel_gmbus.c-939-
drivers/gpu/drm/i915/display/intel_gmbus.c:940: bus->adapter.dev.parent = &pdev->dev;
drivers/gpu/drm/i915/display/intel_gmbus.c-941- bus->display = display;
--
drivers/gpu/drm/radeon/radeon_i2c.c=903=struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
--
drivers/gpu/drm/radeon/radeon_i2c.c-920- i2c->adapter.owner = THIS_MODULE;
drivers/gpu/drm/radeon/radeon_i2c.c:921: i2c->adapter.dev.parent = dev->dev;
drivers/gpu/drm/radeon/radeon_i2c.c-922- i2c->dev = dev;
--
drivers/hid/hid-mcp2221.c=1237=static int mcp2221_probe(struct hid_device *hdev,
--
drivers/hid/hid-mcp2221.c-1299- mcp->adapter.retries = 1;
drivers/hid/hid-mcp2221.c:1300: mcp->adapter.dev.parent = &hdev->dev;
drivers/hid/hid-mcp2221.c-1301- ACPI_COMPANION_SET(&mcp->adapter.dev, ACPI_COMPANION(hdev->dev.parent));
--
drivers/i2c/busses/i2c-ali1535.c=486=static int ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-ali1535.c-496- /* set up the sysfs linkage to our parent device */
drivers/i2c/busses/i2c-ali1535.c:497: ali1535_adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-ali1535.c-498-
--
drivers/i2c/busses/i2c-ali1563.c=396=static int ali1563_probe(struct pci_dev *dev,
--
drivers/i2c/busses/i2c-ali1563.c-403- goto exit;
drivers/i2c/busses/i2c-ali1563.c:404: ali1563_adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-ali1563.c-405- snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name),
--
drivers/i2c/busses/i2c-ali15x3.c=473=static int ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-ali15x3.c-483- /* set up the sysfs linkage to our parent device */
drivers/i2c/busses/i2c-ali15x3.c:484: ali15x3_adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-ali15x3.c-485-
--
drivers/i2c/busses/i2c-altera.c=383=static int altr_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-altera.c-452- idev->adapter.algo = &altr_i2c_algo;
drivers/i2c/busses/i2c-altera.c:453: idev->adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-altera.c-454- idev->adapter.dev.of_node = pdev->dev.of_node;
--
drivers/i2c/busses/i2c-amd8111.c=422=static int amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-amd8111.c-452- /* set up the sysfs linkage to our parent device */
drivers/i2c/busses/i2c-amd8111.c:453: smbus->adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-amd8111.c-454-
--
drivers/i2c/busses/i2c-at91-core.c=196=static int at91_twi_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-at91-core.c-232- dev->adapter.class = I2C_CLASS_DEPRECATED;
drivers/i2c/busses/i2c-at91-core.c:233: dev->adapter.dev.parent = dev->dev;
drivers/i2c/busses/i2c-at91-core.c-234- dev->adapter.nr = pdev->id;
--
drivers/i2c/busses/i2c-axxia.c=720=static int axxia_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-axxia.c-777- idev->adapter.quirks = &axxia_i2c_quirks;
drivers/i2c/busses/i2c-axxia.c:778: idev->adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-axxia.c-779- idev->adapter.dev.of_node = pdev->dev.of_node;
--
drivers/i2c/busses/i2c-cht-wc.c=426=static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-cht-wc.c-451- sizeof(adap->adapter.name));
drivers/i2c/busses/i2c-cht-wc.c:452: adap->adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-cht-wc.c-453-
--
drivers/i2c/busses/i2c-diolan-u2c.c=430=static int diolan_u2c_probe(struct usb_interface *interface,
--
drivers/i2c/busses/i2c-diolan-u2c.c-464-
drivers/i2c/busses/i2c-diolan-u2c.c:465: dev->adapter.dev.parent = &dev->interface->dev;
drivers/i2c/busses/i2c-diolan-u2c.c-466-
--
drivers/i2c/busses/i2c-dln2.c=187=static int dln2_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-dln2.c-209- dln2->adapter.quirks = &dln2_i2c_quirks;
drivers/i2c/busses/i2c-dln2.c:210: dln2->adapter.dev.parent = dev;
drivers/i2c/busses/i2c-dln2.c-211- ACPI_COMPANION_SET(&dln2->adapter.dev, ACPI_COMPANION(&pdev->dev));
--
drivers/i2c/busses/i2c-fsi.c=677=static int fsi_i2c_probe(struct fsi_device *fsi_dev)
--
drivers/i2c/busses/i2c-fsi.c-720- port->adapter.dev.of_node = np;
drivers/i2c/busses/i2c-fsi.c:721: port->adapter.dev.parent = dev;
drivers/i2c/busses/i2c-fsi.c-722- port->adapter.algo = &fsi_i2c_algorithm;
--
drivers/i2c/busses/i2c-i801.c=1537=static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-i801.c-1549- priv->adapter.algo = &smbus_algorithm;
drivers/i2c/busses/i2c-i801.c:1550: priv->adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-i801.c-1551- acpi_use_parent_companion(&priv->adapter.dev);
--
drivers/i2c/busses/i2c-icy.c=121=static int icy_probe(struct zorro_dev *z,
--
drivers/i2c/busses/i2c-icy.c-139- dev_set_drvdata(&z->dev, i2c);
drivers/i2c/busses/i2c-icy.c:140: i2c->adapter.dev.parent = &z->dev;
drivers/i2c/busses/i2c-icy.c-141- i2c->adapter.owner = THIS_MODULE;
--
drivers/i2c/busses/i2c-isch.c=274=static int smbus_sch_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-isch.c-292- /* Set up the sysfs linkage to our parent device */
drivers/i2c/busses/i2c-isch.c:293: priv->adapter.dev.parent = dev;
drivers/i2c/busses/i2c-isch.c-294- priv->adapter.owner = THIS_MODULE;
--
drivers/i2c/busses/i2c-ismt.c=883=ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-ismt.c-898- priv->adapter.algo = &smbus_algorithm;
drivers/i2c/busses/i2c-ismt.c:899: priv->adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-ismt.c-900- ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
--
drivers/i2c/busses/i2c-microchip-corei2c.c=538=static int mchp_corei2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-microchip-corei2c.c-602- idev->adapter.algo = &mchp_corei2c_algo;
drivers/i2c/busses/i2c-microchip-corei2c.c:603: idev->adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-microchip-corei2c.c-604- idev->adapter.dev.of_node = pdev->dev.of_node;
--
drivers/i2c/busses/i2c-mv64xxx.c=977=mv64xxx_i2c_probe(struct platform_device *pd)
--
drivers/i2c/busses/i2c-mv64xxx.c-1035-
drivers/i2c/busses/i2c-mv64xxx.c:1036: drv_data->adapter.dev.parent = &pd->dev;
drivers/i2c/busses/i2c-mv64xxx.c-1037- drv_data->adapter.algo = &mv64xxx_i2c_algo;
--
drivers/i2c/busses/i2c-nct6694.c=145=static int nct6694_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-nct6694.c-175- data->adapter.quirks = &nct6694_i2c_quirks;
drivers/i2c/busses/i2c-nct6694.c:176: data->adapter.dev.parent = dev;
drivers/i2c/busses/i2c-nct6694.c-177- data->adapter.algo_data = data;
--
drivers/i2c/busses/i2c-nforce2.c=304=static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg,
--
drivers/i2c/busses/i2c-nforce2.c-340- smbus->adapter.algo_data = smbus;
drivers/i2c/busses/i2c-nforce2.c:341: smbus->adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-nforce2.c-342- snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
--
drivers/i2c/busses/i2c-nvidia-gpu.c=272=static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-nvidia-gpu.c-306- i2cd->adapter.quirks = &gpu_i2c_quirks;
drivers/i2c/busses/i2c-nvidia-gpu.c:307: i2cd->adapter.dev.parent = dev;
drivers/i2c/busses/i2c-nvidia-gpu.c-308- status = i2c_add_adapter(&i2cd->adapter);
--
drivers/i2c/busses/i2c-parport.c=264=static void i2c_parport_attach(struct parport *port)
--
drivers/i2c/busses/i2c-parport.c-320- adapter->adapter.algo_data = &adapter->algo_data;
drivers/i2c/busses/i2c-parport.c:321: adapter->adapter.dev.parent = port->physport->dev;
drivers/i2c/busses/i2c-parport.c-322-
--
drivers/i2c/busses/i2c-pasemi-core.c=423=int pasemi_i2c_common_probe(struct pasemi_smbus *smbus)
--
drivers/i2c/busses/i2c-pasemi-core.c-433- /* set up the sysfs linkage to our parent device */
drivers/i2c/busses/i2c-pasemi-core.c:434: smbus->adapter.dev.parent = smbus->dev;
drivers/i2c/busses/i2c-pasemi-core.c-435- smbus->use_irq = 0;
--
drivers/i2c/busses/i2c-pnx.c=607=static int i2c_pnx_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-pnx.c-621-
drivers/i2c/busses/i2c-pnx.c:622: alg_data->adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-pnx.c-623- alg_data->adapter.algo = &pnx_algorithm;
--
drivers/i2c/busses/i2c-scmi.c=356=static int smbus_cmi_probe(struct platform_device *device)
--
drivers/i2c/busses/i2c-scmi.c-388- smbus_cmi->adapter.class = I2C_CLASS_HWMON;
drivers/i2c/busses/i2c-scmi.c:389: smbus_cmi->adapter.dev.parent = &device->dev;
drivers/i2c/busses/i2c-scmi.c-390-
--
drivers/i2c/busses/i2c-sis5595.c=367=static int sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-sis5595.c-376- /* set up the sysfs linkage to our parent device */
drivers/i2c/busses/i2c-sis5595.c:377: sis5595_adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-sis5595.c-378-
--
drivers/i2c/busses/i2c-sis630.c=508=static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-sis630.c-516- /* set up the sysfs linkage to our parent device */
drivers/i2c/busses/i2c-sis630.c:517: sis630_adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-sis630.c-518-
--
drivers/i2c/busses/i2c-sis96x.c=242=static int sis96x_probe(struct pci_dev *dev,
--
drivers/i2c/busses/i2c-sis96x.c-279- /* set up the sysfs linkage to our parent device */
drivers/i2c/busses/i2c-sis96x.c:280: sis96x_adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-sis96x.c-281-
--
drivers/i2c/busses/i2c-sun6i-p2wi.c=183=static int p2wi_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-sun6i-p2wi.c-255- init_completion(&p2wi->complete);
drivers/i2c/busses/i2c-sun6i-p2wi.c:256: p2wi->adapter.dev.parent = dev;
drivers/i2c/busses/i2c-sun6i-p2wi.c-257- p2wi->adapter.algo = &p2wi_algo;
--
drivers/i2c/busses/i2c-synquacer.c=535=static int synquacer_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-synquacer.c-584- i2c_set_adapdata(&i2c->adapter, i2c);
drivers/i2c/busses/i2c-synquacer.c:585: i2c->adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-synquacer.c-586- i2c->adapter.dev.of_node = pdev->dev.of_node;
--
drivers/i2c/busses/i2c-tegra-bpmp.c=283=static int tegra_bpmp_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-tegra-bpmp.c-310- i2c->adapter.algo = &tegra_bpmp_i2c_algo;
drivers/i2c/busses/i2c-tegra-bpmp.c:311: i2c->adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-tegra-bpmp.c-312- i2c->adapter.dev.of_node = pdev->dev.of_node;
--
drivers/i2c/busses/i2c-tegra.c=2268=static int tegra_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-tegra.c-2341- i2c_dev->adapter.dev.of_node = i2c_dev->dev->of_node;
drivers/i2c/busses/i2c-tegra.c:2342: i2c_dev->adapter.dev.parent = i2c_dev->dev;
drivers/i2c/busses/i2c-tegra.c-2343- i2c_dev->adapter.retries = 1;
--
drivers/i2c/busses/i2c-tiny-usb.c=216=static int i2c_tiny_usb_probe(struct usb_interface *interface,
--
drivers/i2c/busses/i2c-tiny-usb.c-261-
drivers/i2c/busses/i2c-tiny-usb.c:262: dev->adapter.dev.parent = &dev->interface->dev;
drivers/i2c/busses/i2c-tiny-usb.c-263-
--
drivers/i2c/busses/i2c-via.c=86=static int vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-via.c-123- /* set up the sysfs linkage to our parent device */
drivers/i2c/busses/i2c-via.c:124: vt586b_adapter.dev.parent = &dev->dev;
drivers/i2c/busses/i2c-via.c-125-
--
drivers/i2c/busses/i2c-viapro.c=311=static int vt596_probe(struct pci_dev *pdev,
--
drivers/i2c/busses/i2c-viapro.c-406-
drivers/i2c/busses/i2c-viapro.c:407: vt596_adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-viapro.c-408- snprintf(vt596_adapter.name, sizeof(vt596_adapter.name),
--
drivers/i2c/busses/i2c-xlp9xx.c=506=static int xlp9xx_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-xlp9xx.c-535- init_completion(&priv->msg_complete);
drivers/i2c/busses/i2c-xlp9xx.c:536: priv->adapter.dev.parent = &pdev->dev;
drivers/i2c/busses/i2c-xlp9xx.c-537- priv->adapter.algo = &xlp9xx_i2c_algo;
--
drivers/infiniband/hw/hfi1/qsfp.c=104=static struct hfi1_i2c_bus *init_i2c_bus(struct hfi1_devdata *dd,
--
drivers/infiniband/hw/hfi1/qsfp.c-126- bus->adapter.algo_data = &bus->algo;
drivers/infiniband/hw/hfi1/qsfp.c:127: bus->adapter.dev.parent = &dd->pcidev->dev;
drivers/infiniband/hw/hfi1/qsfp.c-128- snprintf(bus->adapter.name, sizeof(bus->adapter.name),
--
drivers/input/keyboard/pinephone-keyboard.c=320=static int ppkb_probe(struct i2c_client *client)
--
drivers/input/keyboard/pinephone-keyboard.c-378- ppkb->adapter.algo_data = client;
drivers/input/keyboard/pinephone-keyboard.c:379: ppkb->adapter.dev.parent = dev;
drivers/input/keyboard/pinephone-keyboard.c-380- ppkb->adapter.dev.of_node = i2c_bus;
--
drivers/media/dvb-frontends/cx24123.c=1041=struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
--
drivers/media/dvb-frontends/cx24123.c-1084- state->tuner_i2c_adapter.algo_data = NULL;
drivers/media/dvb-frontends/cx24123.c:1085: state->tuner_i2c_adapter.dev.parent = i2c->dev.parent;
drivers/media/dvb-frontends/cx24123.c-1086- i2c_set_adapdata(&state->tuner_i2c_adapter, state);
--
drivers/media/dvb-frontends/zd1301_demod.c=454=static int zd1301_demod_probe(struct platform_device *pdev)
--
drivers/media/dvb-frontends/zd1301_demod.c-495- dev->adapter.algo_data = NULL;
drivers/media/dvb-frontends/zd1301_demod.c:496: dev->adapter.dev.parent = pdev->dev.parent;
drivers/media/dvb-frontends/zd1301_demod.c-497- i2c_set_adapdata(&dev->adapter, dev);
--
drivers/media/pci/zoran/zoran_card.c=698=static int zoran_register_i2c(struct zoran *zr)
--
drivers/media/pci/zoran/zoran_card.c-705- zr->i2c_adapter.algo_data = &zr->i2c_algo;
drivers/media/pci/zoran/zoran_card.c:706: zr->i2c_adapter.dev.parent = &zr->pci_dev->dev;
drivers/media/pci/zoran/zoran_card.c-707- return i2c_bit_add_bus(&zr->i2c_adapter);
--
drivers/media/radio/si4713/radio-usb-si4713.c=400=static int si4713_register_i2c_adapter(struct si4713_usb_device *radio)
--
drivers/media/radio/si4713/radio-usb-si4713.c-403- /* set up sysfs linkage to our parent device */
drivers/media/radio/si4713/radio-usb-si4713.c:404: radio->i2c_adapter.dev.parent = &radio->usbdev->dev;
drivers/media/radio/si4713/radio-usb-si4713.c-405- i2c_set_adapdata(&radio->i2c_adapter, radio);
--
drivers/media/usb/go7007/go7007-i2c.c=204=int go7007_i2c_init(struct go7007 *go)
--
drivers/media/usb/go7007/go7007-i2c.c-207- sizeof(go7007_adap_templ));
drivers/media/usb/go7007/go7007-i2c.c:208: go->i2c_adapter.dev.parent = go->dev;
drivers/media/usb/go7007/go7007-i2c.c-209- i2c_set_adapdata(&go->i2c_adapter, go);
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1169- mutex_init(&usb->i2c_lock);
drivers/media/usb/go7007/go7007-usb.c:1170: go->i2c_adapter.dev.parent = go->dev;
drivers/media/usb/go7007/go7007-usb.c-1171- i2c_set_adapdata(&go->i2c_adapter, go);
--
drivers/media/usb/hdpvr/hdpvr-i2c.c=180=int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
--
drivers/media/usb/hdpvr/hdpvr-i2c.c-184- dev->i2c_adapter = hdpvr_i2c_adapter_template;
drivers/media/usb/hdpvr/hdpvr-i2c.c:185: dev->i2c_adapter.dev.parent = &dev->udev->dev;
drivers/media/usb/hdpvr/hdpvr-i2c.c-186-
--
drivers/video/fbdev/cyber2000fb.c=1263=static int cyber2000fb_i2c_register(struct cfb_info *cfb)
--
drivers/video/fbdev/cyber2000fb.c-1268- cfb->i2c_adapter.algo_data = &cfb->i2c_algo;
drivers/video/fbdev/cyber2000fb.c:1269: cfb->i2c_adapter.dev.parent = cfb->fb.device;
drivers/video/fbdev/cyber2000fb.c-1270- cfb->i2c_algo.setsda = cyber2000fb_i2c_setsda;
--
drivers/video/fbdev/matrox/i2c-matroxfb.c=102=static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
--
drivers/video/fbdev/matrox/i2c-matroxfb.c-114- b->adapter.algo_data = &b->bac;
drivers/video/fbdev/matrox/i2c-matroxfb.c:115: b->adapter.dev.parent = &minfo->pcidev->dev;
drivers/video/fbdev/matrox/i2c-matroxfb.c-116- b->bac = matrox_i2c_algo_template;
--
drivers/video/fbdev/nvidia/nv_i2c.c=84=static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name,
--
drivers/video/fbdev/nvidia/nv_i2c.c-92- chan->adapter.algo_data = &chan->algo;
drivers/video/fbdev/nvidia/nv_i2c.c:93: chan->adapter.dev.parent = &chan->par->pci_dev->dev;
drivers/video/fbdev/nvidia/nv_i2c.c-94- chan->algo.setsda = nvidia_gpio_setsda;
--
drivers/w1/slaves/w1_ds28e17.c=681=static int w1_f19_add_slave(struct w1_slave *sl)
--
drivers/w1/slaves/w1_ds28e17.c-723- sl->name);
drivers/w1/slaves/w1_ds28e17.c:724: data->adapter.dev.parent = &sl->dev;
drivers/w1/slaves/w1_ds28e17.c-725- data->adapter.quirks = &w1_f19_i2c_adapter_quirks;
]
|
| 120/2 |
2026/07/30 12:30 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 105934
output: 19
thoughts: 248
Thoughts: **Analyzing I2C Device Parent Assignment in USB Media Drivers**
Okay, my initial observation is that I've spotted a pattern across several USB media drivers. Specifically, I see examples in `drivers/media/radio/si4713/radio-usb-si4713.c`, `drivers/media/usb/hdpvr/hdpvr-i2c.c`, and `drivers/media/usb/go7007/go7007-usb.c` where the I2C adapter's device parent is being set. It looks like each one uses a slightly different approach but shares the same underlying goal.
My immediate question is how `go->dev` resolves to a `struct device *`. I know it's pointing to either `&intf->dev` or `&usbdev->dev`, but I need to quickly refresh my understanding here. Let's dig into the `hdpvr` driver for a concrete example, as it appears to directly use `&dev->udev->dev`. I need to confirm that `hdpvr` handles unregistration correctly, especially given this parent assignment strategy. I suspect it might defer unregistration, or have some specific logic related to this. To confirm this I need to check the `hdpvr_disconnect` function.
|
| 121/2 |
2026/07/30 12:30 |
tool |
grepper |
0m
Args: map[Expression:hdpvr_disconnect]
Results: map[Output:drivers/media/usb/hdpvr/hdpvr-core.c=264=static int hdpvr_probe(struct usb_interface *interface,
--
drivers/media/usb/hdpvr/hdpvr-core.c-400-
drivers/media/usb/hdpvr/hdpvr-core.c:401:static void hdpvr_disconnect(struct usb_interface *interface)
drivers/media/usb/hdpvr/hdpvr-core.c-402-{
--
drivers/media/usb/hdpvr/hdpvr-core.c=427=static struct usb_driver hdpvr_usb_driver = {
--
drivers/media/usb/hdpvr/hdpvr-core.c-429- .probe = hdpvr_probe,
drivers/media/usb/hdpvr/hdpvr-core.c:430: .disconnect = hdpvr_disconnect,
drivers/media/usb/hdpvr/hdpvr-core.c-431- .id_table = hdpvr_table,
]
|
| 122/2 |
2026/07/30 12:31 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 106762
output: 45
thoughts: 11
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**Analyzing the Command: `hdpvr_disconnect`**
Alright, let's dive into this. "hdpvr_disconnect"... immediately my mind goes to the likely implications. Given the name, I'm expecting this command to be involved in severing a connection, presumably related to an HDPVR β a High Definition Personal Video Recorder. The immediate questions that spring to mind are: *What* is being disconnected? Is this a hardware connection (e.g., physical cable removal) or a software-level disconnect (e.g., stopping a stream, unmounting a network share)? Is this command part of a larger management framework or a standalone utility? What are the potential side effects - data corruption, orphaned processes, system instability if not handled carefully? I'll need to consider this in light of the likely context, and I'll need to look at whether it might be part of a pipeline. What are the dependencies? I'm already anticipating the need to cross-reference with related tools and configurations. I'm also assessing potential error conditions and graceful handling. If it's a software disconnect, I need to know about the shutdown routines. If it's a hardware disconnect, I'm thinking about how the system handles hot-swapping and if there are any specific shutdown sequences required to ensure the system doesn't crash. My next step will be to examine the implementation of `hdpvr_disconnect` itself. I need the specifics of its interaction with the kernel, device drivers, and any relevant user-space applications. And from the name, it's pretty clear it's going to be something very specific. I can't wait to see the details.
|
| 123/2 |
2026/07/30 12:31 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/hdpvr/hdpvr-core.c FirstLine:401 LineCount:30]
Results: map[Contents: 401: static void hdpvr_disconnect(struct usb_interface *interface)
402: {
403: struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface));
404:
405: v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
406: video_device_node_name(&dev->video_dev));
407: /* prevent more I/O from starting and stop any ongoing */
408: mutex_lock(&dev->io_mutex);
409: dev->status = STATUS_DISCONNECTED;
410: wake_up_interruptible(&dev->wait_data);
411: wake_up_interruptible(&dev->wait_buffer);
412: mutex_unlock(&dev->io_mutex);
413: v4l2_device_disconnect(&dev->v4l2_dev);
414: msleep(100);
415: flush_work(&dev->worker);
416: mutex_lock(&dev->io_mutex);
417: hdpvr_cancel_queue(dev);
418: mutex_unlock(&dev->io_mutex);
419: #if IS_ENABLED(CONFIG_I2C)
420: i2c_del_adapter(&dev->i2c_adapter);
421: #endif
422: video_unregister_device(&dev->video_dev);
423: atomic_dec(&dev_nr);
424: }
425:
426:
427: static struct usb_driver hdpvr_usb_driver = {
428: .name = "hdpvr",
429: .probe = hdpvr_probe,
430: .disconnect = hdpvr_disconnect,
]
|
| 124/2 |
2026/07/30 12:31 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 107724
output: 25
thoughts: 46
Thoughts: Okay, here's my interpretation of those thoughts, presented as a personal thought process, as requested:
**Debugging I2C Adapter Disconnection**
Right, so that `hdpvr_disconnect` function... I need to be careful here. I just remembered that it calls `i2c_del_adapter` synchronously! That's a crucial piece of information. Since it's synchronous, that pretty much rules out the `hdpvr` module as the source of my problem, or at least, this isn't the primary area of focus. I need to look elsewhere for the root cause of the adapter disconnection. Okay, time to look for the next likely suspect.
Now, let's see... what else is on the radar? Ah, yes. `radio-usb-si4713.c`. I have a feeling that might be a better lead. Let me dig into that module next and see what its handling of the I2C adapter looks like. I'll check its disconnect routines specifically. I'm hoping I can find a flaw in the I2C handling there that helps explain the behavior I'm seeing.
|
| 125/2 |
2026/07/30 12:31 |
tool |
grepper |
0m
Error:
Args: map[Expression:si4713_usb_device_disconnect]
Results:
|
| 126/2 |
2026/07/30 12:31 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 108051
output: 46
thoughts: 23
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Diving into the Si4713 USB Driver**
Alright, time to get my hands dirty. I need to refresh my memory on the specifics of how the Si4713 radio chip interacts with the system via USB. Specifically, I should start by taking a close look at the `usb_driver` within the `radio-usb-si4713.c` source file. This is where the core logic will reside β the device probe, disconnect handling, data transfer mechanisms, USB descriptor parsing, and all the nitty-gritty details of the USB communication protocol for this particular device family. Knowing that driver code will give me the best insight into its design decisions. This is where I'll probably find the critical data structures and how they are populated, any potential hardware idiosyncrasies the driver has accounted for, and most importantly, how the driver handles potential USB errors or device states. This is my starting point for understanding its operational behavior.
|
| 127/2 |
2026/07/30 12:31 |
tool |
grepper |
0m
Args: map[Expression:usb_driver PathPrefix:drivers/media/radio/si4713/radio-usb-si4713.c]
Results: map[Output:drivers/media/radio/si4713/radio-usb-si4713.c=500=static void usb_si4713_disconnect(struct usb_interface *intf)
--
drivers/media/radio/si4713/radio-usb-si4713.c-514-/* USB subsystem interface */
drivers/media/radio/si4713/radio-usb-si4713.c:515:static struct usb_driver usb_si4713_driver = {
drivers/media/radio/si4713/radio-usb-si4713.c-516- .name = "radio-usb-si4713",
--
drivers/media/radio/si4713/radio-usb-si4713.c-521-
drivers/media/radio/si4713/radio-usb-si4713.c:522:module_usb_driver(usb_si4713_driver);
]
|
| 128/2 |
2026/07/30 12:31 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 108601
output: 51
thoughts: 15
Thoughts: Okay, let's dive into this. Here's my take on `usb_si4713_disconnect`, breaking down my thought process as I, an expert, would:
**Dissecting `usb_si4713_disconnect`**
Alright, I see the task: to analyze this `usb_si4713_disconnect` function. My initial assumption, given the name, is that it's related to cleanly removing or detaching a device β specifically, a Si4713-based USB device. The naming convention is pretty standard, making that assumption quite solid. Now, my mind immediately jumps to a checklist: What resources are being managed? USB devices, especially those interfacing with audio or radio, often have multiple layers: the USB connection itself, perhaps a specific driver instance, potentially even audio playback streams or radio frequency controls. The disconnect function *should* handle the graceful shutdown of all of these, not just the raw USB connection. I need to look for calls to functions that release USB descriptors, stop any data transfer endpoints, unregister the device from the system, release any mutexes or semaphores protecting shared resources, and free any allocated memory associated with the device's state.
I'm also curious about error handling. Is there any attempt to gracefully handle the case where the device is unexpectedly disconnected? A robust disconnect routine would likely check for and handle errors reported by lower-level USB APIs, logging the errors appropriately or even attempting some sort of fallback or retry mechanism if feasible. Furthermore, what about race conditions? This function, or at least its underlying device data structures, is likely being accessed concurrently by multiple threads β the USB interrupt handler, application threads, perhaps even system management threads. Therefore, I must expect and look for synchronization primitives like mutexes or spinlocks to ensure data integrity and avoid crashes during the disconnection process. In addition, I will want to think through the scenarios where a disconnect can happen. What are the various scenarios that may arise, such as a user pressing "eject", a USB cable being pulled, or a system shutdown. Does the code adequately handle all of them? Finally, I need to verify that this function aligns with the overall driver architecture. Does it follow established best practices for USB device handling? Does it adhere to the relevant specifications and standards? That is my framework for evaluation.
|
| 129/2 |
2026/07/30 12:31 |
tool |
read-file |
0m
Args: map[File:drivers/media/radio/si4713/radio-usb-si4713.c FirstLine:500 LineCount:20]
Results: map[Contents: 500: static void usb_si4713_disconnect(struct usb_interface *intf)
501: {
502: struct si4713_usb_device *radio = to_si4713_dev(usb_get_intfdata(intf));
503:
504: dev_info(&intf->dev, "Si4713 development board now disconnected\n");
505:
506: mutex_lock(&radio->lock);
507: usb_set_intfdata(intf, NULL);
508: video_unregister_device(&radio->vdev);
509: v4l2_device_disconnect(&radio->v4l2_dev);
510: mutex_unlock(&radio->lock);
511: v4l2_device_put(&radio->v4l2_dev);
512: }
513:
514: /* USB subsystem interface */
515: static struct usb_driver usb_si4713_driver = {
516: .name = "radio-usb-si4713",
517: .probe = usb_si4713_probe,
518: .disconnect = usb_si4713_disconnect,
519: .id_table = usb_si4713_usb_device_table,
]
|
| 130/2 |
2026/07/30 12:31 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 109544
output: 50
thoughts: 62
Thoughts: **Debugging the SI4713 USB Disconnect**
Okay, here's what's running through my head. I've been tracing the disconnect sequence for this SI4713 USB device, and it's become clear: `usb_si4713_disconnect` doesn't actually handle the unregistering of the I2C adapter. That's a key piece I was missing! Now, I need to figure out *where* that crucial `i2c_del_adapter` call is actually happening, or *should* be happening. Hmm, let me think... where does the lifecycle of this I2C adapter get managed? Let's quickly review the standard places for device cleanup. I need to check `v4l2_device_put` and the driver's release callback function - those seem like the most likely candidates for handling the de-registration of the I2C adapter when the device is removed. Time to go dig in those functions!
|
| 131/2 |
2026/07/30 12:31 |
tool |
grepper |
0m
Args: map[Expression:i2c_del_adapter PathPrefix:drivers/media/radio/si4713/radio-usb-si4713.c]
Results: map[Output:drivers/media/radio/si4713/radio-usb-si4713.c=128=static void usb_si4713_video_device_release(struct v4l2_device *v4l2_dev)
--
drivers/media/radio/si4713/radio-usb-si4713.c-132-
drivers/media/radio/si4713/radio-usb-si4713.c:133: i2c_del_adapter(adapter);
drivers/media/radio/si4713/radio-usb-si4713.c-134- v4l2_device_unregister(&radio->v4l2_dev);
--
drivers/media/radio/si4713/radio-usb-si4713.c=411=static int usb_si4713_probe(struct usb_interface *intf,
--
drivers/media/radio/si4713/radio-usb-si4713.c-490-del_adapter:
drivers/media/radio/si4713/radio-usb-si4713.c:491: i2c_del_adapter(adapter);
drivers/media/radio/si4713/radio-usb-si4713.c-492-err_i2cdev:
]
|
| 132/2 |
2026/07/30 12:31 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 110218
output: 51
thoughts: 298
Thoughts: **My Analysis of the Si4713 USB Radio Driver's Device Release**
Okay, so I've been tracing the driver's lifecycle and release path for the Si4713 USB radio. The key is understanding when `usb_si4713_video_device_release` gets called. Right, it's triggered when the *last* reference to the `v4l2_dev` is dropped. And that happens when the user closes the corresponding `/dev/radioX` file descriptor. Makes sense.
So, user opens the radio device, then unplugs the USB device. Now `usb_si4713_disconnect` gets called. This disconnect function unregisters the video device and disconnects `v4l2_dev`. But hold on, the `v4l2_dev`'s reference count is *still* greater than zero because the file descriptor is still open. This is crucial: that means `i2c_del_adapter` is *not* called at this point. That's good.
But, the `usb_device` itself... that's managed by the USB core. It gets freed when the USB device is physically disconnected. Ah, that's right, the USB core handles that. But hang on... let's see. The I2C adapter... the parent of `radio->i2c_adapter.dev` is set to `&radio->usbdev->dev;`. The parent! So, it points to the device structure itself. When the USB device disappears, so does the reference to the usbdev.
Wait, `usbdev` is a `struct usb_device`. Does it get freed then? Yes, yes it does. When the device is physically disconnected, the USB core drops the reference to it, and it's free game. Aha.
But does `usb_si4713_probe` actually take a reference to `usbdev`? I need to double-check that. Let me quickly review `usb_si4713_probe`. I need to ensure that the probe function doesn't inadvertently hold a reference longer than necessary. I'll check the probe routine to make sure it doesn't leak references, in other words.
|
| 133/2 |
2026/07/30 12:31 |
tool |
read-file |
0m
Args: map[File:drivers/media/radio/si4713/radio-usb-si4713.c FirstLine:411 LineCount:30]
Results: map[Contents: 411: static int usb_si4713_probe(struct usb_interface *intf,
412: const struct usb_device_id *id)
413: {
414: struct si4713_usb_device *radio;
415: struct i2c_adapter *adapter;
416: struct v4l2_subdev *sd;
417: int retval;
418:
419: dev_info(&intf->dev, "Si4713 development board discovered: (%04X:%04X)\n",
420: id->idVendor, id->idProduct);
421:
422: /* Initialize local device structure */
423: radio = kzalloc_obj(struct si4713_usb_device);
424: if (radio)
425: radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
426:
427: if (!radio || !radio->buffer) {
428: dev_err(&intf->dev, "kmalloc for si4713_usb_device failed\n");
429: kfree(radio);
430: return -ENOMEM;
431: }
432:
433: mutex_init(&radio->lock);
434:
435: radio->usbdev = interface_to_usbdev(intf);
436: radio->intf = intf;
437: usb_set_intfdata(intf, &radio->v4l2_dev);
438:
439: retval = si4713_start_seq(radio);
440: if (retval < 0)
]
|
| 134/2 |
2026/07/30 12:31 |
llm |
crash-repro-finder |
1m
Model:
Tokens:
input: 111540
output: 48
thoughts: 125
Thoughts: **The Root of the Issue**
Okay, so I'm looking at this `radio-usb-si4713` driver and it's making a fundamental mistake. It just assigns `interface_to_usbdev(intf)` to `radio->usbdev` directly, without a `usb_get_dev()` call. That's a huge oversight. Essentially, it's not taking a reference to the `usb_device`. This means when the USB device is disconnected β and the USB core handles the cleanup β that `usb_device` is going to be freed. But the I2C adapter, and by extension, this driver, are still registered and their `dev.parent` is now pointing at a *freed* `usb_device`! That, in a nutshell, is the bug. This is exactly where the problem lies. It's a simple driver, but this oversight has some nasty implications. Now, let me just quickly confirm the USB IDs to ensure I'm barking up the right tree...
|
| 135/2 |
2026/07/30 12:32 |
tool |
grepper |
0m
Args: map[Expression:usb_device_id PathPrefix:drivers/media/radio/si4713/radio-usb-si4713.c]
Results: map[Output:drivers/media/radio/si4713/radio-usb-si4713.c=29=MODULE_LICENSE("GPL v2");
--
drivers/media/radio/si4713/radio-usb-si4713.c-39-/* USB Device ID List */
drivers/media/radio/si4713/radio-usb-si4713.c:40:static const struct usb_device_id usb_si4713_usb_device_table[] = {
drivers/media/radio/si4713/radio-usb-si4713.c-41- {USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT,
--
drivers/media/radio/si4713/radio-usb-si4713.c=411=static int usb_si4713_probe(struct usb_interface *intf,
drivers/media/radio/si4713/radio-usb-si4713.c:412: const struct usb_device_id *id)
drivers/media/radio/si4713/radio-usb-si4713.c-413-{
]
|
| 136/2 |
2026/07/30 12:32 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 112248
output: 52
thoughts: 27
Thoughts: Okay, here's my attempt at summarizing those thoughts from an expert's perspective, using a first-person narrative:
**Investigating USB Vendor and Product IDs for SI4713**
Alright, let's get down to brass tacks. First thing's first, I need to verify something fundamental: the specific USB identifiers for the SI4713. I'm going to have to check `USB_SI4713_VENDOR` and `USB_SI4713_PRODUCT`. It's crucial, obviously. Knowing those specific Vendor and Product IDs is the foundational step for proper device recognition and interaction. Without them, even the most elegant driver or application will be dead in the water. I have to make sure these are correctly defined and understood across the whole stack. I'll need these constants to be correct when I'm debugging, and will need to reference them as I build or modify the driver code. It's a quick check, but vital.
|
| 137/2 |
2026/07/30 12:32 |
tool |
grepper |
0m
Args: map[Expression:USB_SI4713_VENDOR PathPrefix:drivers/media/radio/si4713/radio-usb-si4713.c]
Results: map[Output:drivers/media/radio/si4713/radio-usb-si4713.c=29=MODULE_LICENSE("GPL v2");
--
drivers/media/radio/si4713/radio-usb-si4713.c-31-/* The Device announces itself as Cygnal Integrated Products, Inc. */
drivers/media/radio/si4713/radio-usb-si4713.c:32:#define USB_SI4713_VENDOR 0x10c4
drivers/media/radio/si4713/radio-usb-si4713.c-33-#define USB_SI4713_PRODUCT 0x8244
--
drivers/media/radio/si4713/radio-usb-si4713.c=40=static const struct usb_device_id usb_si4713_usb_device_table[] = {
drivers/media/radio/si4713/radio-usb-si4713.c:41: {USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT,
drivers/media/radio/si4713/radio-usb-si4713.c-42- USB_CLASS_HID, 0, 0) },
]
|
| 138/2 |
2026/07/30 12:32 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 112875
output: 35
thoughts: 201
Thoughts: **USB Device Configuration: A Breakdown**
Okay, so I'm looking at vendor `0x10c4`, product `0x8244`. Right, and this needs the `USB_CLASS_HID` interface β that's 0x03. Now, I vaguely remember something about this... Ah, yes! Looking back at `vusb.txt`, I see `usb_device_descriptor_hid` mentions that the `idVendor` and `idProduct` are modified by some Go code.
So, the plan is to bypass that and use `syz_usb_connect` with a custom structure. I've done this before, I *think* I recall that being how this works.
Hang on a second. Didn't I run into a problem earlier? I remember getting a "wrong int arg *prog.UnionType" error when I tried using `ANY`. Right, that's because `ANY` is expecting a union of `ANY` types, and `syzkaller` doesn't directly support `ANY` being used on structs in that way, darn it. Okay, I'll need to go another route...
But wait! `syz_usb_connect` has a `dev ptr[in, string]` argument in the generic definition! *That* should allow me to specify the device details. Okay, let me go back to `vusb.txt` and double-check how that argument is constructed. Hopefully, I've got enough information to craft the right structure and get this test running.
|
| 139/2 |
2026/07/30 12:32 |
tool |
grepper |
0m
Error:
Args: map[Expression:syz_usb_connect\( PathPrefix:sys/linux/vusb.txt]
Results:
|
| 140/2 |
2026/07/30 12:32 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 113460
output: 23
thoughts: 2166
Thoughts: **USB Device Descriptor Conundrum**
Okay, let's break this down. I've been staring at this `vusb.txt` file and I need to reliably emulate a specific USB device, namely the si4713. The immediate issue is the expected data type for the `dev` argument in `syz_usb_connect`. It's clearly not a string, like I initially tried with that `&AUTO` construct. It's expecting a `usb_device_descriptor` struct.
My first thought was, "Great, I can construct the struct!". I started trying to define the `usb_device_descriptor` with the correct values from the si4713. But then the `idVendor` field threw a wrench in the works. It's defined as `const[0, int16]`. I realized I *can't* directly set the vendor ID to `0x10c4` because of that `const` constraint. It appears Syzkaller will override what I provide if it's set to a value other than `0`.
Then I pondered if the `AUTO` keyword would help, but it still expects a USB ID, not a specific value.
I considered `syz_usb_connect$hid` to see if that would automatically patch the device ID. Maybe the syzkaller Go code knows about this specific device (`0x10c4:0x8244`) or can force the HID patching. I can't check `init_vusb.go` directly.
I considered manually crafting a struct that would be compatible with a descriptor using the `&ANY` operator. I got the error `"wrong int arg *prog.UnionType"` meaning I needed to specify which union option. My next idea was using `ANY=@ANYBLOB="1201..."`
I thought, "Can I force the vendor by using `syz_usb_connect` and then `syz_usb_control_io` to manually handle the `GET_DESCRIPTOR` request?" But no, `syz_usb_connect` handles the descriptor internally.
The `usb_device_descriptor` definition is a bit tricky. The struct itself takes the `VENDOR` and `PRODUCT` constants, but that still won't help me control the vendor and product ID. I am still unable to modify the device descriptor and inject raw data.
A potential solution popped in my head. Since I can't directly control the value of `idVendor` and `idProduct`, the *best* option may be to write bytes to a memory location, then pass the address of that memory as the `dev` argument. I planned to do this by using a pipe to write the correct byte values to a specific memory location. However, since I can't manipulate the file descriptors returned by `pipe2` as individual variables, this won't be possible.
Now the question is, can I control which `VENDOR` and `PRODUCT` IDs are generated by `AUTO`?
But *wait*! The device is a HID device. If I use `syz_usb_connect$hid`, syzkaller might patch `idVendor` and `idProduct` for a known HID device. I remembered that si4713 declares: `{USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT, USB_CLASS_HID, 0, 0) }`.
I have to check if `0x10c4:0x8244` is a known HID device in syzkaller. If it is, then `syz_usb_connect$hid` will automatically use it. I need to make sure this happens reliably, though. I am going to search in the driver.
There is a last desperate thought: Are there any other drivers? Could `hdpvr` or `go7007` work? No, not really.
|
| 141/2 |
2026/07/30 12:33 |
tool |
grepper |
0m
Args: map[Expression:go7007_usb_disconnect]
Results: map[Output:drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1327-
drivers/media/usb/go7007/go7007-usb.c:1328:static void go7007_usb_disconnect(struct usb_interface *intf)
drivers/media/usb/go7007/go7007-usb.c-1329-{
--
drivers/media/usb/go7007/go7007-usb.c=1347=static struct usb_driver go7007_usb_driver = {
--
drivers/media/usb/go7007/go7007-usb.c-1349- .probe = go7007_usb_probe,
drivers/media/usb/go7007/go7007-usb.c:1350: .disconnect = go7007_usb_disconnect,
drivers/media/usb/go7007/go7007-usb.c-1351- .id_table = go7007_usb_id_table,
]
|
| 142/2 |
2026/07/30 12:33 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 116848
output: 50
thoughts: 15
Thoughts: Okay, here's my interpretation of that.
**Analyzing the USB Disconnect Scenario**
Alright, let's dive into this `go7007_usb_disconnect` situation. It's a key piece of the puzzle, likely a function responsible for handling the detachment of a USB device associated with the go7007 system. As an expert in embedded systems/drivers, I need to understand what this function does, and how it handles the device being unplugged. My immediate mental checklist starts:
* **Resource Management:** I'm expecting this function to free any allocated resources (buffers, memory, etc.) associated with the disconnected device. Failing to do so can lead to memory leaks, system instability, and ultimately a crash.
* **Interrupt Handling:** How is the interrupt flow managed? Does the function disable interrupts related to the device, acknowledge the disconnection event, and ensure that the system no longer attempts to communicate with the now-absent hardware? Timing is critical here to avoid race conditions.
* **State Transitions:** Disconnection is a state change. The function likely needs to transition the driver and the go7007 system from an active state to an inactive or disconnected state. This requires updating internal flags, potentially signaling to other modules that the device is gone.
* **Error Conditions:** What if the disconnection is unexpected (e.g., a power failure)? Are error checks and handling implemented? Does it gracefully report any errors?
* **Cleanup Procedures:** There's likely some device specific cleanup, like stopping ongoing data transfers, or putting the USB interface back into a known state.
* **Driver Unloading:** Is it responsible for unloading the USB driver, if the device is no longer present?
* **Concurrency:** Any potential threading or multi-process issues? Does this function use mutexes or other synchronization primitives to protect shared data structures?
* **Log Entries:** I want to check for logging. A disconnect event should always be logged, providing invaluable debugging information.
I'll be looking for these aspects, so I can analyze if this function is robust.
|
| 143/2 |
2026/07/30 12:33 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1328 LineCount:20]
Results: map[Contents:1328: static void go7007_usb_disconnect(struct usb_interface *intf)
1329: {
1330: struct go7007 *go = to_go7007(usb_get_intfdata(intf));
1331:
1332: mutex_lock(&go->queue_lock);
1333: mutex_lock(&go->serialize_lock);
1334:
1335: if (go->audio_enabled)
1336: go7007_snd_remove(go);
1337:
1338: go->status = STATUS_SHUTDOWN;
1339: v4l2_device_disconnect(&go->v4l2_dev);
1340: video_unregister_device(&go->vdev);
1341: mutex_unlock(&go->serialize_lock);
1342: mutex_unlock(&go->queue_lock);
1343:
1344: v4l2_device_put(&go->v4l2_dev);
1345: }
1346:
1347: static struct usb_driver go7007_usb_driver = {
]
|
| 144/2 |
2026/07/30 12:33 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 117691
output: 39
thoughts: 38
Thoughts: Okay, here's my take on those thoughts, framed from my expert perspective:
**Debugging I2C Adapter Removal in the go7007_usb Driver**
Right, let me see... I'm looking at this `go7007_usb_disconnect` function, and the code definitely *doesn't* appear to have a call to `i2c_del_adapter`. That's a bit perplexing. This is critical because `i2c_del_adapter` is responsible for properly releasing the I2C adapter resources when a USB device is disconnected. Without it, we're likely going to run into issues; potential resource leaks, perhaps even system instability, are immediate concerns.
So, the immediate question is: *where* is `i2c_del_adapter` actually being called within this module, or perhaps in some other related module? My initial thought is to trace the disconnect flow more thoroughly. Let me check the driver's exit path, see if there's any other cleanup involved, or if any auxiliary module handling the I2C adapter is responsible for this critical cleanup. I'll need to go beyond `go7007_usb_disconnect` itself to track down the responsible call. I need to understand this whole cleanup sequence and ensure no resources are being orphaned. I'll need to get to the bottom of this.
|
| 145/2 |
2026/07/30 12:33 |
tool |
grepper |
0m
Args: map[Expression:i2c_del_adapter PathPrefix:drivers/media/usb/go7007/]
Results: map[Output:drivers/media/usb/go7007/go7007-driver.c=227=static void go7007_remove(struct v4l2_device *v4l2_dev)
--
drivers/media/usb/go7007/go7007-driver.c-234- if (go->i2c_adapter_online) {
drivers/media/usb/go7007/go7007-driver.c:235: i2c_del_adapter(&go->i2c_adapter);
drivers/media/usb/go7007/go7007-driver.c-236- go->i2c_adapter_online = 0;
]
|
| 146/2 |
2026/07/30 12:33 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 118251
output: 46
thoughts: 70
Thoughts: **Eureka! The Problem Domain is Narrowed**
Yes! I've confirmed it. The `go7007_remove` function, just like with the other driver I was investigating, is being called from within `v4l2_device_put`! That's the key: it's triggered when the *last* reference to the device is released. It's the same bug, manifesting in a different driver. Excellent! This is a pattern.
And hang on... `go7007` is a *USB video device*! So, itβs a specific category of devices. Now that I know the code point, I can quickly check the USB IDs and understand the device that is having this issue, and the drivers they are associated with. With that information, I can see how it's interacting with the underlying USB stack, as a starting point for figuring out what's going wrong. This is perfect!
|
| 147/2 |
2026/07/30 12:33 |
tool |
grepper |
0m
Args: map[Expression:usb_device_id PathPrefix:drivers/media/usb/go7007/go7007-usb.c]
Results: map[Output:drivers/media/usb/go7007/go7007-usb.c=469=static const struct go7007_usb_board board_ads_usbav_709 = {
--
drivers/media/usb/go7007/go7007-usb.c-505-
drivers/media/usb/go7007/go7007-usb.c:506:static const struct usb_device_id go7007_usb_id_table[] = {
drivers/media/usb/go7007/go7007-usb.c-507- {
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
drivers/media/usb/go7007/go7007-usb.c:1041: const struct usb_device_id *id)
drivers/media/usb/go7007/go7007-usb.c-1042-{
]
|
| 148/2 |
2026/07/30 12:33 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 118853
output: 49
thoughts: 17
Thoughts: Okay, let's dive into this. Here's my take on those thoughts, as if they're my own:
**Analyzing the USB ID Table: `go7007_usb_id_table`**
Alright, let's see what we've got here. I need to get a handle on the `go7007_usb_id_table`. I'm immediately thinking, this is probably a critical piece of the puzzle for identifying and configuring USB devices related to the go7007 chipset β likely a driver or module setup. Knowing this table's structure is essential, because, like any expert in this area understands, the USB ID table provides the foundation for associating specific hardware vendor and product IDs with the appropriate driver or module. That's a crucial first step for proper device recognition and operation within the system. Is this just a simple lookup table or is it more complex, perhaps including more parameters? I need to look closer to assess the architecture. I'm hoping it's well-documented... but probably not. Time to get digging!
|
| 149/2 |
2026/07/30 12:33 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:506 LineCount:30]
Results: map[Contents: 506: static const struct usb_device_id go7007_usb_id_table[] = {
507: {
508: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
509: USB_DEVICE_ID_MATCH_INT_INFO,
510: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
511: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
512: .bcdDevice_lo = 0x200, /* Revision number of XMen */
513: .bcdDevice_hi = 0x200,
514: .bInterfaceClass = 255,
515: .bInterfaceSubClass = 0,
516: .bInterfaceProtocol = 255,
517: .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN,
518: },
519: {
520: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
521: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
522: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
523: .bcdDevice_lo = 0x202, /* Revision number of Matrix II */
524: .bcdDevice_hi = 0x202,
525: .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II,
526: },
527: {
528: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
529: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
530: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
531: .bcdDevice_lo = 0x204, /* Revision number of Matrix */
532: .bcdDevice_hi = 0x204, /* Reloaded */
533: .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD,
534: },
535: {
]
|
| 150/2 |
2026/07/30 12:33 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 119832
output: 21
thoughts: 3277
Thoughts: **Okay, let's break this down. My initial focus was on figuring out how to trigger a specific USB device configuration (0x0eb1:0x7007) using syzkaller.** I quickly realized that syzkaller's `syz_usb_connect` function and its limited pre-defined device descriptors weren't going to cut it. I pondered whether I could directly manipulate `idVendor` and `idProduct` within the descriptor, but the constants prevented that. The existence of various pre-defined descriptors in syzkaller gave me a hint, but none matched the device I was targeting. The fact that the bug report references kasan reports and not usb errors piqued my interest.
**Then, my thinking shifted. The crash wasn't directly in a USB driver itself, but potentially in something called by it.** I examined the stack trace from the KASAN report, specifically focusing on `usb_register_bus` and its call chain: `blocking_notifier_call_chain`, `mon_notify`, `mon_bus_add`, `mon_bus_init`, `mon_bin_add`, and finally, `device_create`. The `device_create` function allocates a `struct device` and is key. Then I investigated the allocator size of `struct device` which led me to the conclusion that `kobject_uevent_env` could be in the same allocation slot. This is because both were allocated by `kmalloc-4k`. I then investigated the sizes of both these objects.
**The allocation size was clearly the crucial clue.** I honed in on the fact that `kobject_uevent_env` has a sizable buffer (2048 bytes) that would be allocated in a `kmalloc-4k` region, matching the KASAN report's "4096-byte region". Then, I realized that `kobject_uevent_env` is short-lived, meaning the memory it allocated was freed quickly. This strongly suggests a Use-After-Free (UAF) issue, where a previous object allocated in that same 4k slot was freed, then accessed later. The KASAN report pointing to 264 bytes into the freed region gave me a solid indication of what the memory slot had previously held.
**This led me to hypothesize that the original allocation was likely a `struct usb_device`, which is significantly larger than just `struct device` itself.** I checked the size of `struct usb_device`, calculating that it *could* fit within a `kmalloc-4k` region. The key was confirming that a member of that struct would be at or around the KASAN report offset. From the code, I could see that offset 264 in a freed `struct usb_device` pointed to `dev.type` from within `struct device`, perfectly explaining the UAF! To fully confirm this hypothesis I did some manual calculation of offset to verify. Finally, I used external tools to confirm my suspicion about the offset of `dev.type` within `struct usb_device`. I think I have it!
|
| 151/2 |
2026/07/30 12:34 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:devnum OffsetBits:0 SizeBits:32] map[Name:devpath OffsetBits:32 SizeBits:128] map[Name:route OffsetBits:160 SizeBits:32] map[Name:state OffsetBits:192 SizeBits:32] map[Name:speed OffsetBits:224 SizeBits:32] map[Name:rx_lanes OffsetBits:256 SizeBits:32] map[Name:tx_lanes OffsetBits:288 SizeBits:32] map[Name:ssp_rate OffsetBits:320 SizeBits:32] map[Name:tt OffsetBits:384 SizeBits:64] map[Name:ttport OffsetBits:448 SizeBits:32] map[Name:toggle OffsetBits:480 SizeBits:64] map[Name:parent OffsetBits:576 SizeBits:64] map[Name:bus OffsetBits:640 SizeBits:64] map[Name:ep0 OffsetBits:704 SizeBits:704] map[Name:dev OffsetBits:1408 SizeBits:11776] map[Name:descriptor OffsetBits:13184 SizeBits:144] map[Name:bos OffsetBits:13376 SizeBits:64] map[Name:config OffsetBits:13440 SizeBits:64] map[Name:actconfig OffsetBits:13504 SizeBits:64] map[Name:ep_in OffsetBits:13568 SizeBits:1024] map[Name:ep_out OffsetBits:14592 SizeBits:1024] map[Name:rawdescriptors OffsetBits:15616 SizeBits:64] map[Name:bus_mA OffsetBits:15680 SizeBits:16] map[Name:portnum OffsetBits:15696 SizeBits:8] map[Name:level OffsetBits:15704 SizeBits:8] map[Name:devaddr OffsetBits:15712 SizeBits:8] map[Name:can_submit OffsetBits:15720 SizeBits:1] map[Name:persist_enabled OffsetBits:15721 SizeBits:1] map[Name:reset_in_progress OffsetBits:15722 SizeBits:1] map[Name:have_langid OffsetBits:15723 SizeBits:1] map[Name:authorized OffsetBits:15724 SizeBits:1] map[Name:authenticated OffsetBits:15725 SizeBits:1] map[Name:lpm_capable OffsetBits:15726 SizeBits:1] map[Name:lpm_devinit_allow OffsetBits:15727 SizeBits:1] map[Name:usb2_hw_lpm_capable OffsetBits:15728 SizeBits:1] map[Name:usb2_hw_lpm_besl_capable OffsetBits:15729 SizeBits:1] map[Name:usb2_hw_lpm_enabled OffsetBits:15730 SizeBits:1] map[Name:usb2_hw_lpm_allowed OffsetBits:15731 SizeBits:1] map[Name:usb3_lpm_u1_enabled OffsetBits:15732 SizeBits:1] map[Name:usb3_lpm_u2_enabled OffsetBits:15733 SizeBits:1] map[Name:string_langid OffsetBits:15744 SizeBits:32] map[Name:product OffsetBits:15808 SizeBits:64] map[Name:manufacturer OffsetBits:15872 SizeBits:64] map[Name:serial OffsetBits:15936 SizeBits:64] map[Name:filelist OffsetBits:16000 SizeBits:128] map[Name:maxchild OffsetBits:16128 SizeBits:32] map[Name:quirks OffsetBits:16160 SizeBits:32] map[Name:urbnum OffsetBits:16192 SizeBits:32] map[Name:active_duration OffsetBits:16256 SizeBits:64] map[Name:connect_time OffsetBits:16320 SizeBits:64] map[Name:do_remote_wakeup OffsetBits:16384 SizeBits:1] map[Name:reset_resume OffsetBits:16385 SizeBits:1] map[Name:port_is_suspended OffsetBits:16386 SizeBits:1] map[Name:offload_pm_locked OffsetBits:16387 SizeBits:1] map[Name:offload_usage OffsetBits:16416 SizeBits:32] map[Name:offload_lock OffsetBits:16448 SizeBits:1024] map[Name:tunnel_mode OffsetBits:17472 SizeBits:32] map[Name:usb4_link OffsetBits:17536 SizeBits:64] map[Name:slot_id OffsetBits:17600 SizeBits:32] map[Name:l1_params OffsetBits:17632 SizeBits:64] map[Name:u1_params OffsetBits:17696 SizeBits:128] map[Name:u2_params OffsetBits:17824 SizeBits:128] map[Name:lpm_disable_count OffsetBits:17952 SizeBits:32] map[Name:hub_delay OffsetBits:17984 SizeBits:16] map[Name:use_generic_driver OffsetBits:18000 SizeBits:1]]]
|
| 152/2 |
2026/07/30 12:34 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 125282
output: 39
thoughts: 251
Thoughts: **Debugging a USB Driver UAF**
Okay, so `dev` is at offset 1408 bits, which is 176 bytes. Alright, 176 bytes for `dev`. And looking at the structure, `type` is at offset 88 bytes within `struct device`. Now we can calculate: `176 + 88 = 264` bytes. Perfect, exactly 264 bytes. That confirms it, the object is a `struct usb_device`. The UAF is definitely accessing `adapter->dev.parent->type`. This points to a USB driver issue. It's registering an I2C adapter and setting `adapter->dev.parent = &usb_device->dev`, but crucially, it's failing to unregister the I2C adapter during the USB device disconnection!
Now, I need to see which drivers are responsible. I've got `go7007`, `si4713`, and `hdpvr` in mind. Let's see how they handle it. Okay, `hdpvr` correctly unregisters in the `disconnect` function. Good! `si4713` unregisters in `release`. And `go7007` unregisters in `remove`, which is called from `release`. Hmm, that's interesting. Are there any other drivers that might have this vulnerability? Let's take a look at `au0828`.
|
| 153/2 |
2026/07/30 12:34 |
tool |
grepper |
0m
Args: map[Expression:i2c_del_adapter PathPrefix:drivers/media/usb/au0828/]
Results: map[Output:drivers/media/usb/au0828/au0828-i2c.c=388=int au0828_i2c_unregister(struct au0828_dev *dev)
drivers/media/usb/au0828/au0828-i2c.c-389-{
drivers/media/usb/au0828/au0828-i2c.c:390: i2c_del_adapter(&dev->i2c_adap);
drivers/media/usb/au0828/au0828-i2c.c-391- return 0;
]
|
| 154/2 |
2026/07/30 12:34 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 126058
output: 43
thoughts: 17
Thoughts: Here's my thought process, summarized as you requested:
**Unregistering the I2C Adapter: Tracing the Call**
Okay, so I need to figure out where the `au0828_i2c_unregister` function is actually being invoked. I'm dealing with the `au0828` driver, so this is likely a critical step in the I2C adapter's lifecycle, potentially during module unloading or device removal. I need to understand the control flow.
My initial approach will be a code search. I'll need to use my tools β likely grep, or perhaps cscope or ctags if the codebase supports it, to locate all instances where `au0828_i2c_unregister` is directly called. I'm expecting to find it within the `au0828` driver source files, or possibly in related cleanup or shutdown functions.
Once I have a list of call sites, I'll need to analyze the surrounding code. I'll need to understand the conditions under which this unregistration occurs. Is it a graceful shutdown triggered by a specific event, or an error-handling path? Is it called when a device is detached, or when the entire module is unloaded? I'll be looking for clues in the context of the call, specifically at things like device state, error codes, and resource management. I'll probably cross-reference the calls with the device model to check what happens in regards to device power management and registration/deregistration.
Ultimately, my goal is to pinpoint the exact circumstances that trigger the I2C adapter unregistration. This is a crucial piece of the puzzle for understanding the driver's overall behavior and ensuring proper resource cleanup.
|
| 155/2 |
2026/07/30 12:34 |
tool |
grepper |
0m
Args: map[Expression:au0828_i2c_unregister PathPrefix:drivers/media/usb/au0828/]
Results: map[Output:drivers/media/usb/au0828/au0828-core.c=153=void au0828_usb_release(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-core.c-157- /* I2C */
drivers/media/usb/au0828/au0828-core.c:158: au0828_i2c_unregister(dev);
drivers/media/usb/au0828/au0828-core.c-159-
--
drivers/media/usb/au0828/au0828-i2c.c=354=int au0828_i2c_register(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-i2c.c-387-
drivers/media/usb/au0828/au0828-i2c.c:388:int au0828_i2c_unregister(struct au0828_dev *dev)
drivers/media/usb/au0828/au0828-i2c.c-389-{
--
drivers/media/usb/au0828/au0828.h=315=extern int au0828_i2c_register(struct au0828_dev *dev);
drivers/media/usb/au0828/au0828.h:316:extern int au0828_i2c_unregister(struct au0828_dev *dev);
drivers/media/usb/au0828/au0828.h-317-
]
|
| 156/2 |
2026/07/30 12:34 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 126942
output: 41
thoughts: 30
Thoughts: Here's my analysis of the provided snippet, framed as my own thought process:
**Diving into the `au0828_usb_release` Function**
Okay, I'm zeroing in on this `au0828_usb_release` function. My initial question is: what's its purpose within the broader context? It's pretty clear that it has been called somewhere. The critical next step is to trace the call graph. I need to understand the dependencies and where this function is invoked. Finding the calling sites will give me crucial context. I need to figure out the scenarios where resources are being released, which will inform my whole understanding of this module's function.
|
| 157/2 |
2026/07/30 12:34 |
tool |
grepper |
0m
Args: map[Expression:au0828_usb_release PathPrefix:drivers/media/usb/au0828/]
Results: map[Output:drivers/media/usb/au0828/au0828-core.c=125=static void au0828_unregister_media_device(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-core.c-152-
drivers/media/usb/au0828/au0828-core.c:153:void au0828_usb_release(struct au0828_dev *dev)
drivers/media/usb/au0828/au0828-core.c-154-{
--
drivers/media/usb/au0828/au0828-core.c=163=static void au0828_usb_disconnect(struct usb_interface *interface)
--
drivers/media/usb/au0828/au0828-core.c-186- /*
drivers/media/usb/au0828/au0828-core.c:187: * No need to call au0828_usb_release() if V4L2 is enabled,
drivers/media/usb/au0828/au0828-core.c-188- * as this is already called via au0828_usb_v4l2_release()
--
drivers/media/usb/au0828/au0828-core.c-191- }
drivers/media/usb/au0828/au0828-core.c:192: au0828_usb_release(dev);
drivers/media/usb/au0828/au0828-core.c-193-}
--
drivers/media/usb/au0828/au0828-video.c=635=static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
--
drivers/media/usb/au0828/au0828-video.c-642- au0828_usb_v4l2_media_release(dev);
drivers/media/usb/au0828/au0828-video.c:643: au0828_usb_release(dev);
drivers/media/usb/au0828/au0828-video.c-644-}
--
drivers/media/usb/au0828/au0828.h=300=extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
drivers/media/usb/au0828/au0828.h:301:extern void au0828_usb_release(struct au0828_dev *dev);
drivers/media/usb/au0828/au0828.h-302-extern int au0828_debug;
]
|
| 158/2 |
2026/07/30 12:34 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 127928
output: 38
thoughts: 147
Thoughts: **Vulnerability Confirmation and Extension**
Yes! I've confirmed that `au0828` exhibits the exact same vulnerability I suspected! The issue arises because if Video4Linux2 (V4L2) is enabled, which implies that a `/dev/videoX` device is open, the `au0828_usb_disconnect` function preemptively returns and defers the call to `au0828_usb_release` to `au0828_usb_v4l2_release`. This `au0828_usb_v4l2_release` function is then called when the last reference to the `v4l2_dev` structure is dropped, specifically when the file descriptor associated with the `/dev/videoX` device is closed. The timing of those disconnect calls certainly leaves the driver open to abuse in the same way. So, I am confident that `au0828` is, in fact, vulnerable.
Now, a new thought occurs to me... I need to consider `pvrusb2` as well. Does it have the same design?
|
| 159/2 |
2026/07/30 12:34 |
tool |
grepper |
0m
Args: map[Expression:i2c_del_adapter PathPrefix:drivers/media/usb/pvrusb2/]
Results: map[Output:drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c=649=void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-651- if (hdw->i2c_linked) {
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c:652: i2c_del_adapter(&hdw->i2c_adap);
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-653- hdw->i2c_linked = 0;
]
|
| 160/2 |
2026/07/30 12:34 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 128549
output: 42
thoughts: 17
Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert:
**Tracing the Origins of `pvr2_i2c_core_done`**
Right, so, I need to figure out where the `pvr2_i2c_core_done` function is actually being *called* within the system. That's the key to understanding its execution flow and dependencies. I'm going to have to dive into the codebase and start tracing it back. Where is this function's call being initiated? Is it from a driver, a kernel module, or some other part of the I2C subsystem? I need to track down the call sites to get a handle on the triggering conditions, the context in which it operates, and what data is being passed in. It's a fundamental step in analyzing the function's purpose and how it fits into the broader I2C communication scheme used in that particular system. I expect that tracking this down will allow me to reason about any potential race conditions and other edge cases that might be present.
|
| 161/2 |
2026/07/30 12:34 |
tool |
grepper |
0m
Args: map[Expression:pvr2_i2c_core_done PathPrefix:drivers/media/usb/pvrusb2/]
Results: map[Output:drivers/media/usb/pvrusb2/pvrusb2-hdw.c=2705=void pvr2_hdw_disconnect(struct pvr2_hdw *hdw)
--
drivers/media/usb/pvrusb2/pvrusb2-hdw.c-2708- LOCK_TAKE(hdw->big_lock);
drivers/media/usb/pvrusb2/pvrusb2-hdw.c:2709: pvr2_i2c_core_done(hdw);
drivers/media/usb/pvrusb2/pvrusb2-hdw.c-2710- LOCK_TAKE(hdw->ctl_lock);
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c=591=void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-648-
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c:649:void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-650-{
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h=11=void pvr2_i2c_core_init(struct pvr2_hdw *);
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h:12:void pvr2_i2c_core_done(struct pvr2_hdw *);
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h-13-
]
|
| 162/2 |
2026/07/30 12:34 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 129320
output: 594
thoughts: 2519
Thoughts: **Analyzing USB Driver Vulnerability and Reproducer Strategies**
Okay, so the initial assessment is that `pvr2_hdw_disconnect` doesn't seem vulnerable, since it calls `pvr2_i2c_core_done` synchronously. This means we should focus on drivers like `au0828`, `go7007`, and `si4713`. However, the `si4713` is a HID device, and `go7007` and `au0828` are vendor-specific.
The primary target here is `au0828`, specifically with the USB IDs `0x2040:0x7200`. The question becomes, can we emulate the `au0828` device using `syz_usb_connect`? It seems we can't directly target `au0828` with a dedicated `syz_usb_connect` call. However, since `syz_usb_connect` takes `dev ptr[in, usb_device_descriptor]`, the strategy is to construct the `usb_device_descriptor` in memory and pass it.
Initially, I considered using `mmap` and `memcpy`, but `memcpy` is not a syzkaller primitive. The workaround is to use `write` and `read` to pipe data into the mmapped memory. However, `pipe2` returns file descriptors as an array, making it difficult to access the array's contents.
A better approach is to leverage the ability to pass pointers to structs within syzkaller. The `usb_device_descriptor` is defined in `vusb.txt`. Trying to create the struct directly within the program is difficult. However, the existing structure definitions in `vusb.txt` provide a literal. So, can we just use that structure literal and populate its values?
There's a catch: `idVendor` is defined as `const[0, int16]`. Passing `0x2040` directly would likely be rejected. But, what if we use `syz_usb_connect$hid`? The documentation says that `syz_usb_connect$hid` utilizes a `usb_device_descriptor_hid` structure, in which `idVendor` is still `const[0, int16]`. However, the syzkaller Go code patches this value. If syzkaller patches it, does it pick from a list of known HID devices?
The next step is to examine whether `si4713` is in the kernel tree. Yes, `drivers/media/radio/si4713/radio-usb-si4713.c` confirms its presence. Given that syzkaller extracts USB IDs from the kernel, it *should* include `0x10c4:0x8244` in the list of known HID devices because syzkaller extracts all `usb_device_id` tables. Thus, using `syz_usb_connect$hid` will randomly select this device. However, this is not a reliable reproducer.
The next potential workaround is to see if `syz_usb_connect` accepts a string for the `dev` argument. Checking the prompt documentation yields a definition for `syz_usb_connect` which takes `dev ptr[in, string]`. However, testing with `&AUTO='\x12\x01...'` fails due to a "wrong string arg" error.
It looks like the initial documentation might be outdated. Looking into the definition of `syz_usb_connect` in `vusb.txt`, it states that `dev` is, in fact, `ptr[in, usb_device_descriptor]`, implying that a struct, rather than a string, is required. It's also noted that trying to use `&AUTO` won't work because `AUTO` is for pointers to structs, and the `dev` is expecting a struct.
The upshot is that a `usb_device_descriptor` must be provided, and `idVendor` is `const[0, int16]`. However, using `syz_usb_connect` allows the Go code to patch the `idVendor`. Since the goal is to trigger the bug related to `au0828`, can we rely on syzkaller patching the `idVendor` to `0x2040` by letting the `idVendor` and `idProduct` fields use `AUTO` to have syzkaller pick values for them? The reasoning is that syzkaller extracts all USB IDs from the kernel. This also means the correct `usb_device_descriptor` must be provided to trigger the vulnerability. So, a generic struct with `AUTO` for the patchable `
|
| 163/2 |
2026/07/30 12:35 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0x12, 0x1, 0x200, 0, 0, 0, 0x40, 0, 0, 0, 1, 2, 3, 1, [{{0x9, 0x2, 0x19, 1, 1, 0, 0x80, 0xfa, [{{0x9, 0x4, 0, 0, 1, 0xff, 0, 0, 0, [], [{{0x7, 0x5, 0x81, 2, 0x200, 0, 0, 0, []}}]}}]}}]}}, 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 164/2 |
2026/07/30 12:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 133680
output: 433
thoughts: 1837
Thoughts: **Debugging USB Descriptor Structures in Syzkaller**
Okay, so I'm wrestling with how syzkaller is interpreting these USB descriptor structures. It started with a puzzling error, a "wrong array arg *prog.BufferType" message. I need to understand why my struct literals aren't being parsed correctly.
First, I looked at the `usb_config_descriptor`. I saw that it *should* have an `extra` field, which is `void`. In syzkaller, I initially thought `void` fields *weren't* omitted in struct literals, but then I realized that, since it's `void`, it *should* be omitted. The key part is the `interfaces` field, an `array[usb_interface_descriptor, 1:4]`. That's where I thought the problem was, expecting a literal like `[{{0x9, 0x4, ...}}]`.
The `usb_interface_descriptor` itself also threw me for a loop. It's defined as a struct with a single field, `inner`. So, I was initially thinking it should be just `{{0x9, 0x4, ...}}`, but then I remembered that `interfaces` is an *array* of `usb_interface_descriptor`, so it needed the extra set of curly braces: `[{{0x9, 0x4, ...}}]`. The structure definition of `usb_interface_descriptor` eventually unraveled to a type named `usb_interface_descriptor_verbose_t`. Within it, the `extra` field is an `array[usb_interface_extra_descriptor, 0:2]`, and those are unions.
I started to think the problem was with passing an empty array `[]` for `extra`. But then the dreaded `wrong array arg *prog.BufferType` error again. That made me realize that syzkaller expected a buffer, not an array.
Then I realized that `usb_config_descriptor` has an `inner` field. So `[{{...}}]` is an array of `usb_config_descriptor`. And the `usb_device_descriptor` has a `configs` field, which is `array[usb_config_descriptor, 1]`, and so `configs` should be `[{{...}}]`. Inside `usb_config_descriptor`, there is an array of `interfaces` as `array[usb_interface_descriptor, 1:4]`. The problem must be the same as before.
I went back to carefully examine the `usb_config_descriptor_verbose_t` definition, making sure to track the data types and sizes. The fields, in order, are: `bLength`, `bDescriptorType`, `wTotalLength`, `bNumInterfaces`, `bConfigurationValue`, `iConfiguration`, `bmAttributes`, `bMaxPower`, and finally, the array of `interfaces`. Everything lines up! The `EXTRA` is `void`, so it's omitted.
I checked my literal: `{0x9, 0x2, 0x19, 1, 1, 0, 0x80, 0xfa, [{{0x9, 0x4, ...}}]}`. This matches the structure's fields. I still can't explain the `*prog.BufferType` error, despite this. I confirmed that the inner structure is indeed a struct, not a buffer. I'm stumped as to why itβs not working!
Perhaps this has something to do with the specific syzcall I'm calling. Rather than crafting these structs by hand, let me see if I can leverage the existing syzkaller infrastructure. I'll try using `&AUTO=AUTO` with `syz_usb_connect$hid`. It looks like that takes `dev ptr[in, usb_device_descriptor_hid]`, and hopefully, syzkaller will automatically generate a valid struct for me!
|
| 165/2 |
2026/07/30 12:35 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect$hid(3, 0, &AUTO=AUTO, 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 166/2 |
2026/07/30 12:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 136822
output: 536
thoughts: 304
Thoughts: **Syzkaller Syntax Quandary**
Okay, so I'm wrestling with how to handle this struct within the syzkaller context. I initially thought I could simply use `AUTO` for the whole thing, but then I remembered that won't work if it contains any flags or unions. Right, and `&AUTO=AUTO` is clearly invalid syntax. Hmm, but I *can* use just `&AUTO` by itself, which seems promising. Hang on⦠if I'm referencing the pointer `ptr[in, usb_device_descriptor_hid]`, then `&AUTO` should be perfectly acceptable!
Let me double-check the syzkaller syntax just to be sure. Alright, it's defined as `pointer-arg = "&" pointer-arg-addr ["=ANY"] "=" arg`. Wait a minute, the `arg` part is required! That means I have to provide the struct itself... Ugh. But wait, can I get away with `&AUTO={}`? No, that just creates an empty struct.
Okay, let's back up a step. If I try `&AUTO=ANY="..."`, it fails because `ANY` expects a union option, of course. So, what about `&AUTO=ANY=@ANYBLOB="1201..."`? That could be the key!
I need to confirm if `ANYBLOB` is a valid union option within the `ANY` union. Time to go back to the syzkaller documentation. Ah, yes, here it is: `ANY` is indeed a union, containing `ANYRES16`, `ANYRES32`, `ANYRES64`, and the crucial `ANYBLOB`, which is an array of `int8`. So, it looks like `&AUTO=ANY=@ANYBLOB="1201..."` just might be the correct syntax! Now that's the one to try next!
|
| 167/2 |
2026/07/30 12:35 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0x2b, &(0x7f0000000000)=ANY=@ANYBLOB="1201000200000040402000720000010203010902190001010080fa0904000001ff00000007058102000200", 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 168/2 |
2026/07/30 12:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 138231
output: 705
thoughts: 294
Thoughts: **Debugging the Blob Conversion**
Okay, so I'm dealing with `ANYBLOB` here, and immediately I remember that it's defined as `array[int8]`. Therefore, it's expecting an array literal representation β something like `[...]` β and not a raw string. That's the root of the problem.
Let's adjust the argument to reflect this. I need to make sure I format the data as an array of hex values. I think this will work: `&AUTO=ANY=@ANYBLOB=[0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x40, 0x20, 0x00, 0x72, 0x00, 0x00, 0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0xfa, 0x09, 0x04, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00]`. That should be the right format.
|
| 169/2 |
2026/07/30 12:35 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0x2b, &(0x7f0000000000)=ANY=@ANYBLOB=[0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x40, 0x20, 0x00, 0x72, 0x00, 0x00, 0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0xfa, 0x09, 0x04, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x00, 0x02, 0x00], 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 170/2 |
2026/07/30 12:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 139940
output: 626
thoughts: 1046
Thoughts: **Debugging USB Device Descriptor Construction**
Okay, so I'm trying to figure out how to properly define a USB device descriptor for fuzzing. I just realized `ANYBLOB` isn't a valid option for `ANY` in this context. Let's go back and check the definition of `ANY` in syzkaller to be sure. I was hoping I could just use `syz_usb_connect$hid` with `&AUTO=AUTO`, but I remember hitting an issue with `AUTO` and flags before; I got that "wrong type" error. Right, because `AUTO` can't be used directly for flags. I can't just use `&AUTO={}` either, since that would provide an empty struct.
My next idea is that if I focus on `syz_usb_connect$hid`, I can manually construct a valid descriptor, using `AUTO` for the non-flag fields. Looking at the struct definition for `usb_device_descriptor_hid`, I see that `bcdUSB` is a `usb_versions, int16`, so I can provide `0x200` for it. The `bMaxPacketSize0` is `flags[usb_device_max_packet_sizes, int8]`, so I'll provide `64`.
Okay, I'm constructing `usb_device_descriptor_hid`, bit by bit. I need to now construct the nested structs and data. The inner `usb_config_descriptor_hid` has an `interfaces` field, which is an array of `usb_interface_descriptor_hid`. Inside that, there's `extra`, which is a `usb_hid_descriptor_hid`. The `usb_hid_descriptor_hid` has `report_desc`, so I need to construct that. Then there's `endpoints`, which is `usb_endpoint_descriptors_hid`, containing the in and out endpoints.
Now, I'm carefully constructing the full structure, filling in the values I've figured out. I need to make sure I'm matching the correct sizes and data types. I'll construct it, and then I'll use it. Let's try this now and see if I'm on the right track!
|
| 171/2 |
2026/07/30 12:36 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect$hid(3, 0, &AUTO={{0x12, 0x1, 0x200, 0, 0, 0, 64, 0, 0, 0, 1, 2, 3, 1, [{{0x9, 0x2, 0x22, 1, 1, 0, 0x80, 0xfa, [{{0x9, 0x4, 0, 0, 1, 3, 0, 0, 0, {0x9, 0x21, 0x111, 0, 1, {0x22, 0x3f}}, {{{0x7, 0x5, 0x81, 3, 8, 10, 0, 0, []}}, []}}}]}}]}}, 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 172/2 |
2026/07/30 12:36 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 142345
output: 431
thoughts: 1460
Thoughts: **Debugging a USB Configuration Descriptor**
Okay, here we go again with this "wrong array arg" error for `*prog.BufferType`. Why is it treating the `interfaces` field like a buffer when it should be a struct array? Let's trace this. `usb_config_descriptor_hid`... that's where we start. It seems to wrap an `usb_config_descriptor_ifaces_array_t`. Alright, that type definition uses `usb_config_descriptor_t`, which in turn leads to `usb_config_descriptor_verbose_t`. Nested types, got it.
Now, `usb_config_descriptor_verbose_t` defines `interfaces` as `IFS`, and looking at the types, the extra field is `void`, so that is not presented in the resulting struct. This `interfaces` field is the ninth one. But the `usb_config_descriptor_hid` struct is really just a wrapper for `usb_config_descriptor_ifaces_array_t`, which is the nested struct. So, it should be a struct with just one member. The resulting hex looks correct: `{{0x9, 0x2, ...}}`. And `configs` is an array of these. So `configs` would be: `[{{0x9, 0x2, ...}}]`. I have: `[{{0x9, 0x2, 0x22, 1, 1, 0, 0x80, 0xfa, [{{...}}]}}]`.
Wait, maybe `interfaces` isn't an array of structs like I think it is. But, it is defined in the type as `array[usb_interface_descriptor_hid, 1]`. And `usb_interface_descriptor_hid` is another struct. So, this should be: `{{0x9, 0x4, ...}}`. and `interfaces` is `[{{0x9, 0x4, ...}}]`. Exactly what I have! This should work.
Why the "wrong array arg" error? Could it be related to the `len[interfaces, int8]` within `usb_config_descriptor_ifaces_array_t`? It is actually used for `bNumInterfaces`. I am using `1` in the literal, the correct value for the example. And, `len` fields can be `AUTO`. So I could use `AUTO` for all of the fixed-size fields, making this simpler.
Wait, if the parser is expecting a buffer, maybe it's because of `len[interfaces, int8]`.
Let's check `usb_config_descriptor_verbose_t` again. `interfaces` is, indeed, defined as `array[usb_interface_descriptor_hid, 1]`. That *should* be an array of structs.
Why would the parser expect a buffer then? Is `usb_interface_descriptor_hid` somehow resolving to a buffer? No, it's a struct.
Wait... maybe `usb_config_descriptor_hid` isn't what I think it is! Let's check a similar type definition. Hmm, `usb_device_descriptor_hid` uses a similar structure, and looks like the last argument in the nested struct is `array[usb_config_descriptor_hid, 1]`. I don't think I am missing anything here... it is an array of structs.
Wait, I can just cheat and let syzkaller generate the descriptor! Use `syz_usb_connect$hid` with `&AUTO`. But wait, I had that "wrong type" error when I tried `=AUTO`.
Ah, because I used `=AUTO`, that's the problem. What if I just do `syz_usb_connect$hid(3, 0, &AUTO, 0)`? `&AUTO` without an initialization is not valid for a struct pointer. Hmm, but if I don't provide the value, syzkaller will just give me a random valid one! Let's try that... `syz_usb_connect$hid(3, 0, &AUTO, 0)`!
|
| 173/2 |
2026/07/30 12:36 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect$hid(3, 0, &AUTO, 0)
r1 = openat$video0(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat$video1(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat$i2c0(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat$i2c1(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat$i2c2(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat$i2c3(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 174/2 |
2026/07/30 12:36 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 145158
output: 405
thoughts: 63
Thoughts: Here's my take on the situation:
**Debugging a Kernel Interaction in Syzkaller**
Alright, so I was looking at this trace and hit a snag. The system call, `openat$video0`, is throwing a wrench in the works β it's not a recognized syscall. My first thought was, "Darn it! What's going on?"
Then, I had a moment of clarity, remembering that in the Syzkaller context, I don't need those descriptive suffixes. The tool already distinguishes based on other factors. I added that suffix just to differentiate in my mental model, but that's not how it's defined. Duh! I should just be using the standard `openat` syscall.
Time to correct that and see if this solves the problem!
|
| 175/2 |
2026/07/30 12:36 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect$hid(3, 0, &AUTO, 0)
r1 = openat(0xffffffffffffff9c, &AUTO='/dev/video0\x00', 0, 0)
r2 = openat(0xffffffffffffff9c, &AUTO='/dev/video1\x00', 0, 0)
r3 = openat(0xffffffffffffff9c, &AUTO='/dev/i2c-0\x00', 0, 0)
r4 = openat(0xffffffffffffff9c, &AUTO='/dev/i2c-1\x00', 0, 0)
r5 = openat(0xffffffffffffff9c, &AUTO='/dev/i2c-2\x00', 0, 0)
r6 = openat(0xffffffffffffff9c, &AUTO='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 176/2 |
2026/07/30 12:36 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 146740
output: 22
thoughts: 229
Thoughts: **Debugging I2C Device Interaction**
Okay, so I'm hitting some snags with this I2C interface. First, it looks like when dealing with filenames, specifically when I'm escaping them, I need to make sure I'm not using the null byte (`\x00`). That's a classic pitfall. Now, that "out-of-tree result" message - I think that means I can't just pass `r3` into the `ioctl` call if `r3` isn't pointing to a valid resource or if it's not handled by the kernel. Let me think...
Ah, right, `openat` gives me a file descriptor (`fd`), but the `ioctl` function I'm calling, specifically the `I2C_SMBUS` variant, is expecting a dedicated `fd_i2c` type. So, I need to figure out how to reconcile those. I'm going to need to do some casting, or maybe there's a specific `openat$i2c` wrapper call. I'll check if there's such a thing. That would be ideal β a streamlined approach.
Let's look around for that. I'm going to start with the obvious places, namely `sys/linux/dev_i2c.txt` and `sys/linux/fs.txt`. I need to figure out the right way to initialize it so I can pass it to `ioctl`.
Okay, I think I've got it. Can I simply use `openat$i2c(0xffffffffffffff9c, &AUTO='/dev/i2c-0', 0, 0)`? I'll double-check `dev_i2c.txt` and confirm my assumptions about the arguments for this function.
|
| 177/2 |
2026/07/30 12:36 |
tool |
read-description |
0m
Args:
Results: map[Output:# Copyright 2018 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
include <uapi/linux/i2c-dev.h>
include <uapi/linux/i2c.h>
define I2C_MAX_BLOCK_1 (I2C_SMBUS_BLOCK_MAX + 1)
define I2C_MAX_BLOCK_2 (I2C_SMBUS_BLOCK_MAX + 2)
resource fd_i2c[fd]
syz_open_dev$I2C(dev ptr[in, string["/dev/i2c-#"]], id intptr, flags flags[open_flags]) fd_i2c
ioctl$I2C_RETRIES(fd fd_i2c, cmd const[I2C_RETRIES], arg intptr)
ioctl$I2C_TIMEOUT(fd fd_i2c, cmd const[I2C_TIMEOUT], arg intptr)
ioctl$I2C_SLAVE(fd fd_i2c, cmd const[I2C_SLAVE], arg intptr[0:0x3ff])
ioctl$I2C_SLAVE_FORCE(fd fd_i2c, cmd const[I2C_SLAVE_FORCE], arg intptr[0:0x3ff])
ioctl$I2C_TENBIT(fd fd_i2c, cmd const[I2C_TENBIT], arg boolptr)
ioctl$I2C_PEC(fd fd_i2c, cmd const[I2C_PEC], arg intptr)
ioctl$I2C_FUNCS(fd fd_i2c, cmd const[I2C_FUNCS], arg ptr[in, intptr])
ioctl$I2C_RDWR(fd fd_i2c, cmd const[I2C_RDWR], arg ptr[in, i2c_rdwr_ioctl_data])
ioctl$I2C_SMBUS(fd fd_i2c, cmd const[I2C_SMBUS], arg ptr[in, i2c_smbus_ioctl_data])
i2c_smbus_ioctl_data {
read_write bool8
command int8
size int32[I2C_SMBUS_QUICK:I2C_SMBUS_I2C_BLOCK_DATA]
data ptr[in, i2c_smbus_data]
}
i2c_smbus_data {
size int8[0:I2C_MAX_BLOCK_2]
block array[int8, I2C_MAX_BLOCK_1]
}
i2c_rdwr_ioctl_data {
msgs ptr[in, array[i2c_msg]]
nmsgs len[msgs, int32]
}
i2c_msg {
addr int16
flags flags[i2c_msg_flags, int16]
len len[buf, int16]
buf ptr[in, array[int8]]
}
i2c_msg_flags = I2C_M_RD, I2C_M_TEN, I2C_M_DMA_SAFE, I2C_M_RECV_LEN, I2C_M_NO_RD_ACK, I2C_M_IGNORE_NAK, I2C_M_REV_DIR_ADDR, I2C_M_NOSTART, I2C_M_STOP
]
|
| 178/2 |
2026/07/30 12:36 |
llm |
crash-repro-finder |
1m
Model:
Tokens:
input: 148218
output: 22
thoughts: 98
Thoughts: **Initial Assessment & Hypothesis**
Okay, so I've got this system call, `syz_open_dev$I2C`, that takes a device path, an identifier, and some flags, and returns a file descriptor for I2C devices. Got it. Based on that function, I'm thinking I should use `syz_open_dev$I2C` for anything I2C-related. That seems straightforward. Now, the next question is about video devices. My initial hunch is that I'll need something like `syz_open_dev$video`. It makes logical sense, but I need to confirm that. Time to consult `dev_video4linux.txt`. That documentation should have all the details I need to nail down the correct syz call to use.
|
| 179/2 |
2026/07/30 12:37 |
tool |
read-description |
0m
Args: map[File:dev_video4linux.txt]
Results: map[Output:# Copyright 2018 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
include <linux/time.h>
include <linux/types.h>
include <uapi/asm/ioctl.h>
include <uapi/linux/fcntl.h>
include <uapi/linux/videodev2.h>
include <uapi/linux/v4l2-common.h>
include <uapi/linux/v4l2-subdev.h>
include <uapi/linux/v4l2-mediabus.h>
include <uapi/linux/media-bus-format.h>
include <uapi/linux/v4l2-controls.h>
include <uapi/linux/media.h>
resource fd_video[fd]
resource fd_v4l2_buffer[fd]
syz_open_dev$video(dev ptr[in, string["/dev/video#"]], id intptr, flags flags[open_flags]) fd_video
syz_open_dev$video4linux(dev ptr[in, string["/dev/v4l-subdev#"]], id intptr, flags flags[open_flags]) fd_video
# TODO: we now get wrong values for ioctl commands that involve v4l2_buffer and v4l2_event.
# Our definition uses 32-bit timespec, while kernel uses 64-bit timespec when __KERNEL__ is defined.
# Special support for CONFIG_VIDEO_VIMC/VIM2M/VIVID/VICODEC.
# Here we assume that all of them are enabled and the following arguments are passed on command line:
# vivid.n_devs=16 vivid.multiplanar=1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2
openat$vimc0(fd const[AT_FDCWD], file ptr[in, string["/dev/video0"]], flags const[O_RDWR], mode const[0]) fd_video
openat$vimc1(fd const[AT_FDCWD], file ptr[in, string["/dev/video1"]], flags const[O_RDWR], mode const[0]) fd_video
openat$vimc2(fd const[AT_FDCWD], file ptr[in, string["/dev/video2"]], flags const[O_RDWR], mode const[0]) fd_video
syz_open_dev$vivid(dev ptr[in, string["/dev/video#"]], id proc[3, 4], flags const[O_RDWR]) fd_video
openat$vicodec0(fd const[AT_FDCWD], file ptr[in, string["/dev/video36"]], flags const[O_RDWR], mode const[0]) fd_video
openat$vicodec1(fd const[AT_FDCWD], file ptr[in, string["/dev/video37"]], flags const[O_RDWR], mode const[0]) fd_video
# TODO: there are some complex rules as to what ioctl's are applicable to what devices
# (see determine_valid_ioctls in v4l2-dev.c). We don't have these rules described.
# Currently we just apply all ioctl's to all v4l devices.
syz_open_dev$swradio(dev ptr[in, string["/dev/swradio#"]], id proc[0, 2], flags const[O_RDWR]) fd_video
syz_open_dev$radio(dev ptr[in, string["/dev/radio#"]], id proc[0, 4], flags const[O_RDWR]) fd_video
syz_open_dev$vbi(dev ptr[in, string["/dev/vbi#"]], id proc[0, 4], flags const[O_RDWR]) fd_video
ioctl$VIDIOC_QUERYCAP(fd fd_video, cmd const[VIDIOC_QUERYCAP], arg ptr[out, v4l2_capability])
ioctl$VIDIOC_ENUM_FMT(fd fd_video, cmd const[VIDIOC_ENUM_FMT], arg ptr[inout, v4l2_fmtdesc[v4l2_buf_type]])
ioctl$VIDIOC_G_FMT(fd fd_video, cmd const[VIDIOC_G_FMT], arg ptr[inout, v4l2_format[v4l2_buf_type]])
ioctl$VIDIOC_S_FMT(fd fd_video, cmd const[VIDIOC_S_FMT], arg ptr[inout, v4l2_format[v4l2_buf_type]])
ioctl$VIDIOC_REQBUFS(fd fd_video, cmd const[VIDIOC_REQBUFS], arg ptr[inout, v4l2_requestbuffers[v4l2_buf_type]])
# This variant serves as fd_v4l2_buffer constructor.
# Potentially more ioctl can create fd_v4l2_buffer, but the kernel code is hard to understand.
ioctl$VIDIOC_QUERYBUF_DMABUF(fd fd_video, cmd const[VIDIOC_QUERYBUF], arg ptr[inout, v4l2_buffer[v4l2_buf_type, V4L2_MEMORY_DMABUF, fd_v4l2_buffer]])
ioctl$VIDIOC_QUERYBUF(fd fd_video, cmd const[VIDIOC_QUERYBUF], arg ptr[inout, v4l2_buffer_t[v4l2_buf_type]])
ioctl$VIDIOC_G_FBUF(fd fd_video, cmd const[VIDIOC_G_FBUF], arg ptr[inout, v4l2_framebuffer])
ioctl$VIDIOC_S_FBUF(fd fd_video, cmd const[VIDIOC_S_FBUF], arg ptr[in, v4l2_framebuffer])
ioctl$VIDIOC_OVERLAY(fd fd_video, cmd const[VIDIOC_OVERLAY], arg ptr[in, int32])
ioctl$VIDIOC_QBUF(fd fd_video, cmd const[VIDIOC_QBUF], arg ptr[inout, v4l2_buffer_t[v4l2_buf_type]])
ioctl$VIDIOC_EXPBUF(fd fd_video, cmd const[VIDIOC_EXPBUF], arg ptr[inout, v4l2_exportbuffer[v4l2_buf_type]])
ioctl$VIDIOC_DQBUF(fd fd_video, cmd const[VIDIOC_DQBUF], arg ptr[inout, v4l2_buffer_t[v4l2_buf_type]])
ioctl$VIDIOC_STREAMON(fd fd_video, cmd const[VIDIOC_STREAMON], arg ptr[in, int32])
ioctl$VIDIOC_STREAMOFF(fd fd_video, cmd const[VIDIOC_STREAMOFF], arg ptr[in, int32])
ioctl$VIDIOC_G_PARM(fd fd_video, cmd const[VIDIOC_G_PARM], arg ptr[inout, v4l2_streamparm])
ioctl$VIDIOC_S_PARM(fd fd_video, cmd const[VIDIOC_S_PARM], arg ptr[inout, v4l2_streamparm])
ioctl$VIDIOC_G_STD(fd fd_video, cmd const[VIDIOC_G_STD], arg ptr[out, v4l2_std_id])
ioctl$VIDIOC_S_STD(fd fd_video, cmd const[VIDIOC_S_STD], arg ptr[in, v4l2_std_id])
ioctl$VIDIOC_ENUMSTD(fd fd_video, cmd const[VIDIOC_ENUMSTD], arg ptr[inout, v4l2_standard])
ioctl$VIDIOC_ENUMINPUT(fd fd_video, cmd const[VIDIOC_ENUMINPUT], arg ptr[inout, v4l2_input])
ioctl$VIDIOC_G_CTRL(fd fd_video, cmd const[VIDIOC_G_CTRL], arg ptr[inout, v4l2_control])
ioctl$VIDIOC_S_CTRL(fd fd_video, cmd const[VIDIOC_S_CTRL], arg ptr[inout, v4l2_control])
ioctl$VIDIOC_G_TUNER(fd fd_video, cmd const[VIDIOC_G_TUNER], arg ptr[inout, v4l2_tuner])
ioctl$VIDIOC_S_TUNER(fd fd_video, cmd const[VIDIOC_S_TUNER], arg ptr[in, v4l2_tuner])
ioctl$VIDIOC_G_AUDIO(fd fd_video, cmd const[VIDIOC_G_AUDIO], arg ptr[out, v4l2_audio])
ioctl$VIDIOC_S_AUDIO(fd fd_video, cmd const[VIDIOC_S_AUDIO], arg ptr[in, v4l2_audio])
ioctl$VIDIOC_QUERYCTRL(fd fd_video, cmd const[VIDIOC_QUERYCTRL], arg ptr[inout, v4l2_queryctrl])
ioctl$VIDIOC_QUERYMENU(fd fd_video, cmd const[VIDIOC_QUERYMENU], arg ptr[inout, v4l2_querymenu])
ioctl$VIDIOC_G_INPUT(fd fd_video, cmd const[VIDIOC_G_INPUT], arg ptr[out, int32])
ioctl$VIDIOC_S_INPUT(fd fd_video, cmd const[VIDIOC_S_INPUT], arg ptr[inout, int32])
ioctl$VIDIOC_G_EDID(fd fd_video, cmd const[VIDIOC_G_EDID], arg ptr[inout, v4l2_edid])
ioctl$VIDIOC_S_EDID(fd fd_video, cmd const[VIDIOC_S_EDID], arg ptr[inout, v4l2_edid])
ioctl$VIDIOC_G_OUTPUT(fd fd_video, cmd const[VIDIOC_G_OUTPUT], arg ptr[out, int32])
ioctl$VIDIOC_S_OUTPUT(fd fd_video, cmd const[VIDIOC_S_OUTPUT], arg ptr[inout, int32])
ioctl$VIDIOC_ENUMOUTPUT(fd fd_video, cmd const[VIDIOC_ENUMOUTPUT], arg ptr[inout, v4l2_output])
ioctl$VIDIOC_G_AUDOUT(fd fd_video, cmd const[VIDIOC_G_AUDOUT], arg ptr[out, v4l2_audioout])
ioctl$VIDIOC_S_AUDOUT(fd fd_video, cmd const[VIDIOC_S_AUDOUT], arg ptr[in, v4l2_audioout])
ioctl$VIDIOC_G_MODULATOR(fd fd_video, cmd const[VIDIOC_G_MODULATOR], arg ptr[inout, v4l2_modulator])
ioctl$VIDIOC_S_MODULATOR(fd fd_video, cmd const[VIDIOC_S_MODULATOR], arg ptr[in, v4l2_modulator])
ioctl$VIDIOC_G_FREQUENCY(fd fd_video, cmd const[VIDIOC_G_FREQUENCY], arg ptr[inout, v4l2_frequency])
ioctl$VIDIOC_S_FREQUENCY(fd fd_video, cmd const[VIDIOC_S_FREQUENCY], arg ptr[in, v4l2_frequency])
ioctl$VIDIOC_CROPCAP(fd fd_video, cmd const[VIDIOC_CROPCAP], arg ptr[inout, v4l2_cropcap])
ioctl$VIDIOC_G_CROP(fd fd_video, cmd const[VIDIOC_G_CROP], arg ptr[inout, v4l2_crop])
ioctl$VIDIOC_S_CROP(fd fd_video, cmd const[VIDIOC_S_CROP], arg ptr[in, v4l2_crop])
ioctl$VIDIOC_G_JPEGCOMP(fd fd_video, cmd const[VIDIOC_G_JPEGCOMP], arg ptr[out, v4l2_jpegcompression])
ioctl$VIDIOC_S_JPEGCOMP(fd fd_video, cmd const[VIDIOC_S_JPEGCOMP], arg ptr[in, v4l2_jpegcompression])
ioctl$VIDIOC_QUERYSTD(fd fd_video, cmd const[VIDIOC_QUERYSTD], arg ptr[out, v4l2_std_id])
ioctl$VIDIOC_TRY_FMT(fd fd_video, cmd const[VIDIOC_TRY_FMT], arg ptr[inout, v4l2_format[v4l2_buf_type]])
ioctl$VIDIOC_ENUMAUDIO(fd fd_video, cmd const[VIDIOC_ENUMAUDIO], arg ptr[inout, v4l2_audio])
ioctl$VIDIOC_ENUMAUDOUT(fd fd_video, cmd const[VIDIOC_ENUMAUDOUT], arg ptr[inout, v4l2_audioout])
ioctl$VIDIOC_G_PRIORITY(fd fd_video, cmd const[VIDIOC_G_PRIORITY], arg flags[v4l2_priority])
ioctl$VIDIOC_S_PRIORITY(fd fd_video, cmd const[VIDIOC_S_PRIORITY], arg flags[v4l2_priority])
ioctl$VIDIOC_G_SLICED_VBI_CAP(fd fd_video, cmd const[VIDIOC_G_SLICED_VBI_CAP], arg ptr[inout, v4l2_sliced_vbi_cap])
ioctl$VIDIOC_LOG_STATUS(fd fd_video, cmd const[VIDIOC_LOG_STATUS], arg const[0])
ioctl$VIDIOC_G_EXT_CTRLS(fd fd_video, cmd const[VIDIOC_G_EXT_CTRLS], arg ptr[inout, v4l2_ext_controls])
ioctl$VIDIOC_S_EXT_CTRLS(fd fd_video, cmd const[VIDIOC_S_EXT_CTRLS], arg ptr[inout, v4l2_ext_controls])
ioctl$VIDIOC_TRY_EXT_CTRLS(fd fd_video, cmd const[VIDIOC_TRY_EXT_CTRLS], arg ptr[inout, v4l2_ext_controls])
ioctl$VIDIOC_ENUM_FRAMESIZES(fd fd_video, cmd const[VIDIOC_ENUM_FRAMESIZES], arg ptr[inout, v4l2_frmsizeenum])
ioctl$VIDIOC_ENUM_FRAMEINTERVALS(fd fd_video, cmd const[VIDIOC_ENUM_FRAMEINTERVALS], arg ptr[inout, v4l2_frmivalenum])
ioctl$VIDIOC_G_ENC_INDEX(fd fd_video, cmd const[VIDIOC_G_ENC_INDEX], arg ptr[out, v4l2_enc_idx])
ioctl$VIDIOC_ENCODER_CMD(fd fd_video, cmd const[VIDIOC_ENCODER_CMD], arg ptr[inout, v4l2_encoder_cmd])
ioctl$VIDIOC_TRY_ENCODER_CMD(fd fd_video, cmd const[VIDIOC_TRY_ENCODER_CMD], arg ptr[inout, v4l2_encoder_cmd])
ioctl$VIDIOC_DBG_S_REGISTER(fd fd_video, cmd const[VIDIOC_DBG_S_REGISTER], arg ptr[in, v4l2_dbg_register])
ioctl$VIDIOC_DBG_G_REGISTER(fd fd_video, cmd const[VIDIOC_DBG_G_REGISTER], arg ptr[inout, v4l2_dbg_register])
ioctl$VIDIOC_S_HW_FREQ_SEEK(fd fd_video, cmd const[VIDIOC_S_HW_FREQ_SEEK], arg ptr[in, v4l2_hw_freq_seek])
ioctl$VIDIOC_S_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_S_DV_TIMINGS], arg ptr[inout, v4l2_dv_timings])
ioctl$VIDIOC_G_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_G_DV_TIMINGS], arg ptr[inout, v4l2_dv_timings])
ioctl$VIDIOC_DQEVENT(fd fd_video, cmd const[VIDIOC_DQEVENT], arg ptr[out, v4l2_event])
ioctl$VIDIOC_SUBSCRIBE_EVENT(fd fd_video, cmd const[VIDIOC_SUBSCRIBE_EVENT], arg ptr[in, v4l2_event_subscription])
ioctl$VIDIOC_UNSUBSCRIBE_EVENT(fd fd_video, cmd const[VIDIOC_UNSUBSCRIBE_EVENT], arg ptr[in, v4l2_event_subscription])
ioctl$VIDIOC_CREATE_BUFS(fd fd_video, cmd const[VIDIOC_CREATE_BUFS], arg ptr[inout, v4l2_create_buffers[v4l2_buf_type]])
ioctl$VIDIOC_PREPARE_BUF(fd fd_video, cmd const[VIDIOC_PREPARE_BUF], arg ptr[inout, v4l2_buffer_t[v4l2_buf_type]])
ioctl$VIDIOC_G_SELECTION(fd fd_video, cmd const[VIDIOC_G_SELECTION], arg ptr[inout, v4l2_selection])
ioctl$VIDIOC_S_SELECTION(fd fd_video, cmd const[VIDIOC_S_SELECTION], arg ptr[inout, v4l2_selection])
ioctl$VIDIOC_DECODER_CMD(fd fd_video, cmd const[VIDIOC_DECODER_CMD], arg ptr[inout, v4l2_decoder_cmd])
ioctl$VIDIOC_TRY_DECODER_CMD(fd fd_video, cmd const[VIDIOC_TRY_DECODER_CMD], arg ptr[inout, v4l2_decoder_cmd])
ioctl$VIDIOC_ENUM_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_ENUM_DV_TIMINGS], arg ptr[inout, v4l2_enum_dv_timings])
ioctl$VIDIOC_QUERY_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_QUERY_DV_TIMINGS], arg ptr[out, v4l2_dv_timings])
ioctl$VIDIOC_DV_TIMINGS_CAP(fd fd_video, cmd const[VIDIOC_DV_TIMINGS_CAP], arg ptr[inout, v4l2_dv_timings_cap])
ioctl$VIDIOC_ENUM_FREQ_BANDS(fd fd_video, cmd const[VIDIOC_ENUM_FREQ_BANDS], arg ptr[inout, v4l2_frequency_band])
ioctl$VIDIOC_DBG_G_CHIP_INFO(fd fd_video, cmd const[VIDIOC_DBG_G_CHIP_INFO], arg ptr[inout, v4l2_dbg_chip_info])
ioctl$VIDIOC_QUERY_EXT_CTRL(fd fd_video, cmd const[VIDIOC_QUERY_EXT_CTRL], arg ptr[inout, v4l2_query_ext_ctrl])
ioctl$VIDIOC_SUBDEV_G_FMT(fd fd_video, cmd const[VIDIOC_SUBDEV_G_FMT], arg ptr[inout, v4l2_subdev_format])
ioctl$VIDIOC_SUBDEV_S_FMT(fd fd_video, cmd const[VIDIOC_SUBDEV_S_FMT], arg ptr[inout, v4l2_subdev_format])
ioctl$VIDIOC_SUBDEV_G_FRAME_INTERVAL(fd fd_video, cmd const[VIDIOC_SUBDEV_G_FRAME_INTERVAL], arg ptr[inout, v4l2_subdev_frame_interval])
ioctl$VIDIOC_SUBDEV_S_FRAME_INTERVAL(fd fd_video, cmd const[VIDIOC_SUBDEV_S_FRAME_INTERVAL], arg ptr[inout, v4l2_subdev_frame_interval])
ioctl$VIDIOC_SUBDEV_ENUM_MBUS_CODE(fd fd_video, cmd const[VIDIOC_SUBDEV_ENUM_MBUS_CODE], arg ptr[inout, v4l2_subdev_mbus_code_enum])
ioctl$VIDIOC_SUBDEV_ENUM_FRAME_SIZE(fd fd_video, cmd const[VIDIOC_SUBDEV_ENUM_FRAME_SIZE], arg ptr[inout, v4l2_subdev_frame_size_enum])
ioctl$VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL(fd fd_video, cmd const[VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL], arg ptr[inout, v4l2_subdev_frame_interval_enum])
ioctl$VIDIOC_SUBDEV_G_CROP(fd fd_video, cmd const[VIDIOC_SUBDEV_G_CROP], arg ptr[inout, v4l2_subdev_crop])
ioctl$VIDIOC_SUBDEV_S_CROP(fd fd_video, cmd const[VIDIOC_SUBDEV_S_CROP], arg ptr[inout, v4l2_subdev_crop])
ioctl$VIDIOC_SUBDEV_G_SELECTION(fd fd_video, cmd const[VIDIOC_SUBDEV_G_SELECTION], arg ptr[inout, v4l2_subdev_selection])
ioctl$VIDIOC_SUBDEV_S_SELECTION(fd fd_video, cmd const[VIDIOC_SUBDEV_S_SELECTION], arg ptr[inout, v4l2_subdev_selection])
ioctl$VIDIOC_SUBDEV_G_EDID(fd fd_video, cmd const[VIDIOC_SUBDEV_G_EDID], arg ptr[inout, v4l2_edid])
ioctl$VIDIOC_SUBDEV_S_EDID(fd fd_video, cmd const[VIDIOC_SUBDEV_S_EDID], arg ptr[inout, v4l2_edid])
ioctl$VIDIOC_SUBDEV_S_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_SUBDEV_S_DV_TIMINGS], arg ptr[inout, v4l2_dv_timings])
ioctl$VIDIOC_SUBDEV_G_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_SUBDEV_G_DV_TIMINGS], arg ptr[inout, v4l2_dv_timings])
ioctl$VIDIOC_SUBDEV_ENUM_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_SUBDEV_ENUM_DV_TIMINGS], arg ptr[inout, v4l2_enum_dv_timings])
ioctl$VIDIOC_SUBDEV_QUERY_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_SUBDEV_QUERY_DV_TIMINGS], arg ptr[out, v4l2_dv_timings])
ioctl$VIDIOC_SUBDEV_DV_TIMINGS_CAP(fd fd_video, cmd const[VIDIOC_SUBDEV_DV_TIMINGS_CAP], arg ptr[inout, v4l2_dv_timings_cap])
# Generally we don't specify close on resources,
# but fd_v4l2_buffer is not used as input anywhere else (why is it needed?).
# So this is added to prevent compilation errors.
close$fd_v4l2_buffer(fd fd_v4l2_buffer)
v4l2_capability {
driver array[int8, 16]
card array[int8, 32]
bus_info array[int8, 32]
version int32
capabilities flags[v4l2_capability_capabilities, int32]
device_caps int32
reserved array[const[0, int32], 3]
}
type v4l2_fmtdesc[BUF_TYPE] {
index int32
type flags[BUF_TYPE, int32]
flags flags[v4l2_fmtdesc_flags, int32]
description array[int8, 32]
pixelformat flags[v4l2_pix_format_pixelformat, int32]
reserved array[const[0, int32], 4]
}
type v4l2_format[BUF_TYPE] {
type flags[BUF_TYPE, int32]
fmt v4l2_format_fmt
}
v4l2_format_fmt [
pix v4l2_pix_format
pix_mp v4l2_pix_format_mplane
win v4l2_window
vbi v4l2_vbi_format
sliced v4l2_sliced_vbi_format
sdr v4l2_sdr_format
meta v4l2_meta_format
raw_data array[int8, 200]
]
v4l2_pix_format {
width int32
height int32
pixelformat flags[v4l2_pix_format_pixelformat, int32]
field flags[v4l2_field, int32]
bytesperline int32
sizeimage int32
colorspace flags[v4l2_colorspace, int32]
priv int32
flags flags[v4l2_pix_format_flags, int32]
ycbcr_enc flags[v4l2_ycbcr_encoding, int32]
quantization flags[v4l2_quantization, int32]
xfer_func flags[v4l2_xfer_func, int32]
}
v4l2_pix_format_mplane {
width int32
height int32
pixelformat flags[v4l2_pix_format_pixelformat, int32]
field flags[v4l2_field, int32]
colorspace flags[v4l2_colorspace, int32]
plane_fmt array[v4l2_plane_pix_format, 8]
num_planes int8
flags int8
ycbcr_enc flags[v4l2_ycbcr_encoding, int8]
quantization flags[v4l2_quantization, int8]
xfer_func flags[v4l2_xfer_func, int8]
reserved array[const[0, int8], 7]
} [packed]
v4l2_plane_pix_format {
sizeimage int32
bytesperline int32
reserved array[const[0, int16], 6]
} [packed]
v4l2_window {
w v4l2_rect
field flags[v4l2_field, int32]
chromakey int32
clips ptr[inout, v4l2_clip]
clipcount int32
bitmap buffer[inout]
global_alpha int8
}
v4l2_rect {
left int32
top int32
width int32
height int32
}
v4l2_clip {
c v4l2_rect
next ptr[inout, v4l2_clip, opt]
}
v4l2_vbi_format {
sampling_rate int32
offset int32
samples_per_line int32
sample_format flags[v4l2_pix_format_pixelformat, int32]
start array[int32, 2]
count array[int32, 2]
flags flags[v4l2_vbi_format_flags, int32]
reserved array[const[0, int32], 2]
}
v4l2_sliced_vbi_format {
service_set int16
service_lines array[int16, 48]
io_size int32
reserved array[const[0, int32], 2]
}
v4l2_sdr_format {
pixelformat flags[v4l2_pix_format_pixelformat, int32]
buffersize int32
reserved array[const[0, int8], 24]
} [packed]
v4l2_meta_format {
dataformat flags[v4l2_meta_data_formats, int32]
buffersize int32[0:0x7fffffff]
width int32[0:65535]
height int32[0:65535]
bytesperline int32[0:0x7fffffff]
} [packed]
type v4l2_requestbuffers[BUF_TYPE] {
count int32
type flags[BUF_TYPE, int32]
memory flags[v4l2_memory, int32]
capabilities const[0, int32]
flags int8
reserved array[const[0, int8], 3]
}
type v4l2_buffer_t[BUF_TYPE] [
mmap v4l2_buffer[BUF_TYPE, V4L2_MEMORY_MMAP, intptr]
userptr v4l2_buffer[BUF_TYPE, V4L2_MEMORY_USERPTR, ptr[out, int8]]
overlay v4l2_buffer[BUF_TYPE, V4L2_MEMORY_OVERLAY, int32]
fd v4l2_buffer[BUF_TYPE, V4L2_MEMORY_DMABUF, fd_v4l2_buffer[opt]]
multiplanar_mmap v4l2_buffer[BUF_TYPE, V4L2_MEMORY_MMAP, ptr[inout, array[v4l2_plane[intptr], 2]]]
multiplanar_userptr v4l2_buffer[BUF_TYPE, V4L2_MEMORY_USERPTR, ptr[inout, array[v4l2_plane[ptr[out, int8]], 2]]]
multiplanar_overlay v4l2_buffer[BUF_TYPE, V4L2_MEMORY_OVERLAY, ptr[inout, array[v4l2_plane[int32], 2]]]
multiplanar_fd v4l2_buffer[BUF_TYPE, V4L2_MEMORY_DMABUF, ptr[inout, array[v4l2_plane[fd_v4l2_buffer[opt]], 2]]]
]
# TODO: The field directions needs to be defined. Recursively v4l2_plane, v4l2_plane_union needs checking.
type v4l2_buffer[BUF_TYPE, MEM_TYPE, ARG_TYPE] {
index int32
type flags[BUF_TYPE, int32]
bytesused len[type, int32]
flags flags[v4l2_buffer_flags, int32]
field int32
timestamp timeval
timecode v4l2_timecode
sequence int32
memory const[MEM_TYPE, int32]
m alignptr[ARG_TYPE] (out)
length int32
reserved2 const[0, int32]
request_fd fd_request[opt]
}
v4l2_timecode {
type flags[v4l2_timecode_type, int32]
flags flags[v4l2_timecode_flags, int32]
frames int8
seconds int8
minutes int8
hours int8
userbits array[int8, 4]
}
type v4l2_plane[ARG_TYPE] {
bytesused int32
length int32
m alignptr[ARG_TYPE]
data_offset int32
reserved array[const[0, int32], 11]
}
v4l2_framebuffer {
capability flags[v4l2_framebuffer_capability, int32]
flags flags[v4l2_framebuffer_flags, int32]
base buffer[inout]
fmt v4l2_framebuffer_union
}
v4l2_framebuffer_union {
width int32
height int32
pixelformat flags[v4l2_pix_format_pixelformat, int32]
field flags[v4l2_field, int32]
bytesperline int32
sizeimage int32
colorspace flags[v4l2_colorspace, int32]
priv int32
}
type v4l2_exportbuffer[BUF_TYPE] {
type flags[BUF_TYPE, int32]
index int32
plane int32
flags flags[pipe_flags, int32]
fd fd_dma_buf (out)
reserved array[const[0, int32], 11]
}
v4l2_streamparm {
type flags[v4l2_buf_type, int32]
parm v4l2_streamparm_union
}
v4l2_streamparm_union [
capture v4l2_captureparm
output v4l2_outputparm
raw_data array[int8, 200]
]
v4l2_captureparm {
capability flags[v4l2_captureparm_cap, int32]
capturemode flags[v4l2_captureparm_mode, int32]
timeperframe v4l2_fract
extendedmode int32
readbuffers int32
reserved array[const[0, int32], 4]
}
v4l2_fract {
numerator int32
denominator int32
}
v4l2_outputparm {
capability flags[v4l2_captureparm_cap, int32]
outputmode flags[v4l2_captureparm_mode, int32]
timeperframe v4l2_fract
extendedmode int32
writebuffers int32
reserved array[const[0, int32], 4]
}
v4l2_control {
id int32
value int32
}
v4l2_tuner {
index int32
name array[int8, 32]
type flags[v4l2_tuner_type, int32]
capability flags[v4l2_tuner_capability, int32]
rangelow int32
rangehigh int32
rxsubchans flags[v4l2_tuner_rxsubchans, int32]
audmode flags[v4l2_tuner_audmode, int32]
signal int32
afc int32
reserved array[const[0, int32], 4]
}
v4l2_audio {
index int32
name array[int8, 32]
capability flags[v4l2_audio_capability, int32]
mode flags[v4l2_audio_mode, int32]
reserved array[const[0, int32], 2]
}
v4l2_queryctrl {
id int32
type flags[v4l2_ctrl_type, int32]
name array[int8, 32]
minimum int32
maximum int32
step int32
default_value int32
flags flags[v4l2_control_flags, int32]
reserved array[const[0, int32], 2]
}
v4l2_querymenu {
id int32
index int32
union v4l2_querymenu_union
reserved const[0, int32]
} [packed]
v4l2_querymenu_union [
name array[int8, 32]
value int64
]
v4l2_edid {
pad const[0, int32]
start_block int32
blocks int32
reserved array[const[0, int32], 5]
edid ptr[inout, int8]
}
v4l2_audioout {
index int32
name array[int8, 32]
capability flags[v4l2_audio_capability, int32]
mode flags[v4l2_audio_mode, int32]
reserved array[const[0, int32], 2]
}
v4l2_modulator {
index int32
name array[int8, 32]
capability flags[v4l2_tuner_capability, int32]
rangelow int32
rangehigh int32
txsubchans flags[v4l2_tuner_rxsubchans, int32]
type flags[v4l2_tuner_type, int32]
reserved array[const[0, int32], 3]
}
v4l2_frequency {
tuner int32
type flags[v4l2_tuner_type, int32]
frequency int32
reserved array[const[0, int32], 8]
}
v4l2_cropcap {
type flags[v4l2_buf_type, int32]
bounds v4l2_rect
defrect v4l2_rect
pixelaspect v4l2_fract
}
v4l2_crop {
type flags[v4l2_buf_type, int32]
c v4l2_rect
}
v4l2_jpegcompression {
quality int32
APPn int32[0:15]
APP_len int32[0:60]
APP_data array[int8, 60]
COM_len int32[0:60]
COM_data array[int8, 60]
jpeg_markers flags[v4l2_jpeg_markers, int32]
}
v4l2_sliced_vbi_cap {
service_set int16
service_lines array[int16, 48]
type flags[v4l2_buf_type, int32]
reserved array[const[0, int32], 3]
}
v4l2_ext_controls {
ctrl_class flags[v4l2_ext_ctrl_class, int32]
count int32
error_idx int32
request_fd fd_request[opt] (in)
reserved const[0, int32]
controls ptr[inout, v4l2_ext_control]
}
v4l2_ext_control {
id flags[v4l2_ext_controls, int32]
size int32
reserved2 array[const[0, int32], 1]
union v4l2_ext_u
} [packed]
v4l2_ext_u [
value int32
value64 int64
string ptr[inout, int8]
p_u8 ptr[inout, int8]
p_u16 ptr[inout, int16]
p_u32 ptr[inout, int32]
ptr intptr
]
v4l2_frmsizeenum {
index int32
pixel_format flags[v4l2_pix_format_pixelformat, int32]
type flags[v4l2_frmsizetypes, int32]
union v4l2_frmsizeenum_union
reserved array[const[0, int32], 2]
}
v4l2_frmsizeenum_union [
discrete v4l2_frmsize_discrete
stepwise v4l2_frmsize_stepwise
]
v4l2_frmsize_discrete {
width int32
height int32
}
v4l2_frmsize_stepwise {
min_width int32
max_width int32
step_width int32
min_height int32
max_height int32
step_height int32
}
v4l2_frmivalenum {
index int32
pixel_format flags[v4l2_pix_format_pixelformat, int32]
width int32
height int32
type flags[v4l2_frmivaltypes, int32]
union v4l2_frmivalenum_union
reserved array[const[0, int32], 2]
}
v4l2_frmivalenum_union [
discrete v4l2_fract
stepwise v4l2_frmival_stepwise
]
v4l2_frmival_stepwise {
min v4l2_fract
max v4l2_fract
step v4l2_fract
}
v4l2_enc_idx {
entries int32
entries_cap int32
reserved array[const[0, int32], 4]
entry array[v4l2_enc_idx_entry, 64]
}
v4l2_enc_idx_entry {
offset int64
pts int64
length int32
flags flags[v4l2_enc_idx_flags, int32]
reserved array[const[0, int32], 2]
}
v4l2_dbg_register {
match v4l2_dbg_match
size bytesize[reg, int32]
reg int64
val int64
} [packed]
v4l2_dbg_match {
type flags[v4l2_dbg_match_type, int32]
union v4l2_dbg_match_union
} [packed]
v4l2_dbg_match_union [
addr int32
name array[int8, 32]
]
v4l2_hw_freq_seek {
tuner int32
type flags[v4l2_tuner_type, int32]
seek_upward int32
wrap_around int32
spacing int32
rangelow int32
rangehigh int32
reserved array[const[0, int32], 5]
}
v4l2_dv_timings {
type flags[v4l2_dv_timings_type, int32]
union v4l2_dv_timings_union
} [packed]
v4l2_dv_timings_union [
bt v4l2_bt_timings
reserved array[const[0, int32], 32]
]
v4l2_bt_timings {
width int32
height int32
interlaced flags[v4l2_bt_timings_interlaced, int32]
polarities flags[v4l2_bt_timings_polarities, int32]
pixelclock int64
hfrontporch int32
hsync int32
hbackporch int32
vfrontporch int32
vsync int32
vbackporch int32
il_vfrontporch int32
il_vsync int32
il_vbackporch int32
standards flags[v4l2_bt_timings_standards, int32]
flags flags[v4l2_bt_timings_flags, int32]
picture_aspect v4l2_fract
cea861_vic int8
hdmi_vic int8
reserved array[const[0, int8], 46]
} [packed]
v4l2_encoder_cmd {
cmd flags[v4l2_encoder_cmd_cmd, int32]
flags flags[v4l2_encoder_flags, int32]
data array[int32, 8]
}
v4l2_event {
type flags[v4l2_event_type, int32]
u v4l2_event_union
pending int32
sequence int32
timestamp timespec
id int32
reserved array[const[0, int32], 8]
}
v4l2_event_union [
vsync v4l2_event_vsync
ctrl v4l2_event_ctrl
frame_sync v4l2_event_frame_sync
src_change v4l2_event_src_change
motion_det v4l2_event_motion_det
data array[int8, 64]
]
v4l2_event_vsync {
field flags[v4l2_field_1, int8]
} [packed]
v4l2_event_ctrl {
changes flags[v4l2_event_ctrl_changes, int32]
type flags[v4l2_ctrl_type, int32]
u v4l2_event_ctrl_union
flags int32
minimum int32
maximum int32
step int32
default_value int32
}
v4l2_event_ctrl_union [
value int32
value64 int64
]
v4l2_event_frame_sync {
frame_sequence int32
}
v4l2_event_src_change {
changes flags[v4l2_event_src_changes, int32]
}
v4l2_event_motion_det {
flags flags[v4l2_event_motion_det_flags, int32]
frame_sequence int32
region_mask int32
}
v4l2_event_subscription {
type flags[v4l2_event_type, int32]
id int32
flags flags[v4l2_event_subscription_flags, int32]
reserved array[const[0, int32], 5]
}
type v4l2_create_buffers[BUF_TYPE] {
index int32
count int32
memory flags[v4l2_memory, int32]
format v4l2_format[BUF_TYPE]
capabilities int32
reserved array[const[0, int32], 7]
}
v4l2_selection {
type flags[v4l2_buf_type_1, int32]
target flags[v4l2_selection_target, int32]
flags flags[v4l2_selection_flags, int32]
r v4l2_rect
reserved array[const[0, int32], 9]
}
v4l2_decoder_cmd {
cmd flags[v4l2_decoder_cmd_cmd, int32]
flags flags[v4l2_decoder_cmd_flags, int32]
u v4l2_decoder_cmd_u
}
v4l2_decoder_cmd_u [
stop_pts int64
start v4l2_decoder_cmd_start
raw_data array[int32, 16]
]
v4l2_decoder_cmd_start {
speed int32
format flags[v4l2_decoder_cmd_format, int32]
}
v4l2_enum_dv_timings {
index int32
pad const[0, int32]
reserved array[const[0, int32], 2]
timings v4l2_dv_timings
}
v4l2_dv_timings_cap {
type flags[v4l2_dv_timings_type, int32]
pad const[0, int32]
reserved array[const[0, int32], 2]
u v4l2_dv_timings_cap_u
}
v4l2_dv_timings_cap_u [
bt v4l2_bt_timings_cap
raw_data array[int32, 32]
]
v4l2_bt_timings_cap {
min_width int32
max_width int32
min_height int32
max_height int32
min_pixelclock int64
max_pixelclock int64
standards flags[v4l2_bt_timings_standards, int32]
capabilities flags[v4l2_bt_timings_cap_capabilities, int32]
reserved array[const[0, int32], 16]
} [packed]
v4l2_frequency_band {
tuner int32
type flags[v4l2_tuner_type, int32]
index int32
capability flags[v4l2_tuner_capability, int32]
rangelow int32
rangehigh int32
modulation flags[v4l2_frequency_band_modulation, int32]
reserved array[const[0, int32], 9]
}
v4l2_dbg_chip_info {
match v4l2_dbg_match
name array[int8, 32]
flags flags[v4l2_dbg_chip_info_flags, int32]
reserved array[const[0, int32], 32]
} [packed]
v4l2_query_ext_ctrl {
id flags[v4l2_query_ext_ctrl, int32]
type flags[v4l2_ctrl_type, int32]
name array[int8, 32]
minimum int64
maximum int64
step int64
default_value int64
flags int32
elem_size int32
elems int32
nr_of_dims int32
dims array[int32, 4]
reserved array[const[0, int32], 32]
}
type v4l2_std_id flags[v4l2_std_id, int64]
v4l2_standard {
index int32
id v4l2_std_id
name array[int8, 24]
frameperiod v4l2_fract
framelines int32
reserved array[const[0, int32], 4]
}
v4l2_input {
index int32
name array[int8, 32]
type flags[v4l2_input_type, int32]
audioset int32
tuner flags[v4l2_tuner_type, int32]
std v4l2_std_id
status flags[v4l2_input_status, int32]
capabilities flags[v4l2_input_capabilities, int32]
reserved array[const[0, int32], 3]
}
v4l2_output {
index int32
name array[int8, 32]
type flags[v4l2_output_type, int32]
audioset int32
modulator int32
std v4l2_std_id
capabilities flags[v4l2_output_capabilities, int32]
reserved array[const[0, int32], 3]
}
v4l2_subdev_format {
which flags[v4l2_subdev_format_whence, int32]
pad const[0, int32]
format v4l2_mbus_framefmt
reserved array[const[0, int32], 8]
}
v4l2_mbus_framefmt {
width int32
height int32
code flags[media_bus_fmt, int32]
field flags[v4l2_field, int32]
colorspace flags[v4l2_colorspace, int32]
ycbcr_enc flags[v4l2_ycbcr_encoding, int16]
quantization flags[v4l2_quantization, int16]
xfer_func flags[v4l2_xfer_func, int16]
reserved array[const[0, int16], 11]
}
v4l2_subdev_frame_interval {
pad const[0, int32]
interval v4l2_fract
reserved array[const[0, int32], 9]
}
v4l2_subdev_mbus_code_enum {
pad const[0, int32]
index int32
code flags[media_bus_fmt, int32]
which flags[v4l2_subdev_format_whence, int32]
reserved array[const[0, int32], 8]
}
v4l2_subdev_frame_size_enum {
index int32
pad const[0, int32]
code flags[media_bus_fmt, int32]
min_width int32
max_width int32
min_height int32
max_height int32
which flags[v4l2_subdev_format_whence, int32]
reserved array[const[0, int32], 8]
}
v4l2_subdev_frame_interval_enum {
index int32
pad const[0, int32]
code flags[media_bus_fmt, int32]
width int32
height int32
interval v4l2_fract
which flags[v4l2_subdev_format_whence, int32]
reserved array[const[0, int32], 8]
}
v4l2_subdev_crop {
which flags[v4l2_subdev_format_whence, int32]
pad const[0, int32]
rect v4l2_rect
reserved array[const[0, int32], 8]
}
v4l2_subdev_selection {
which flags[v4l2_subdev_format_whence, int32]
pad const[0, int32]
target flags[v4l2_selection_target, int32]
flags flags[v4l2_selection_flags, int32]
r v4l2_rect
reserved array[const[0, int32], 8]
}
v4l2_jpeg_markers = V4L2_JPEG_MARKER_DHT, V4L2_JPEG_MARKER_DQT, V4L2_JPEG_MARKER_DRI, V4L2_JPEG_MARKER_COM, V4L2_JPEG_MARKER_APP
v4l2_subdev_format_whence = V4L2_SUBDEV_FORMAT_TRY, V4L2_SUBDEV_FORMAT_ACTIVE
v4l2_buf_type_1 = V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OVERLAY, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_BUF_TYPE_VBI_OUTPUT, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, V4L2_BUF_TYPE_SDR_CAPTURE, V4L2_BUF_TYPE_SDR_OUTPUT, V4L2_BUF_TYPE_META_CAPTURE, V4L2_BUF_TYPE_META_OUTPUT
v4l2_field_1 = V4L2_FIELD_ANY, V4L2_FIELD_NONE, V4L2_FIELD_TOP, V4L2_FIELD_BOTTOM
v4l2_field = V4L2_FIELD_INTERLACED, V4L2_FIELD_SEQ_TB, V4L2_FIELD_SEQ_BT, V4L2_FIELD_ALTERNATE, V4L2_FIELD_INTERLACED_TB, V4L2_FIELD_INTERLACED_BT, v4l2_field_1
v4l2_colorspace = V4L2_COLORSPACE_DEFAULT, V4L2_COLORSPACE_SMPTE170M, V4L2_COLORSPACE_SMPTE240M, V4L2_COLORSPACE_REC709, V4L2_COLORSPACE_BT878, V4L2_COLORSPACE_470_SYSTEM_M, V4L2_COLORSPACE_470_SYSTEM_BG, V4L2_COLORSPACE_JPEG, V4L2_COLORSPACE_SRGB, V4L2_COLORSPACE_OPRGB, V4L2_COLORSPACE_BT2020, V4L2_COLORSPACE_RAW, V4L2_COLORSPACE_DCI_P3
v4l2_ycbcr_encoding = V4L2_YCBCR_ENC_DEFAULT, V4L2_YCBCR_ENC_601, V4L2_YCBCR_ENC_709, V4L2_YCBCR_ENC_XV601, V4L2_YCBCR_ENC_XV709, V4L2_YCBCR_ENC_BT2020, V4L2_YCBCR_ENC_BT2020_CONST_LUM, V4L2_YCBCR_ENC_SMPTE240M
v4l2_quantization = V4L2_QUANTIZATION_DEFAULT, V4L2_QUANTIZATION_FULL_RANGE, V4L2_QUANTIZATION_LIM_RANGE
v4l2_xfer_func = V4L2_XFER_FUNC_DEFAULT, V4L2_XFER_FUNC_709, V4L2_XFER_FUNC_SRGB, V4L2_XFER_FUNC_OPRGB, V4L2_XFER_FUNC_SMPTE240M, V4L2_XFER_FUNC_NONE, V4L2_XFER_FUNC_DCI_P3, V4L2_XFER_FUNC_SMPTE2084
v4l2_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, v4l2_buf_type_1
v4l2_memory = V4L2_MEMORY_MMAP, V4L2_MEMORY_USERPTR, V4L2_MEMORY_OVERLAY, V4L2_MEMORY_DMABUF
v4l2_tuner_type = V4L2_TUNER_RADIO, V4L2_TUNER_ANALOG_TV, V4L2_TUNER_DIGITAL_TV, V4L2_TUNER_SDR, V4L2_TUNER_RF
v4l2_ctrl_type = V4L2_CTRL_TYPE_INTEGER, V4L2_CTRL_TYPE_BOOLEAN, V4L2_CTRL_TYPE_MENU, V4L2_CTRL_TYPE_BUTTON, V4L2_CTRL_TYPE_INTEGER64, V4L2_CTRL_TYPE_CTRL_CLASS, V4L2_CTRL_TYPE_STRING, V4L2_CTRL_TYPE_BITMASK, V4L2_CTRL_TYPE_INTEGER_MENU, V4L2_CTRL_COMPOUND_TYPES, V4L2_CTRL_TYPE_U8, V4L2_CTRL_TYPE_U16, V4L2_CTRL_TYPE_U32, V4L2_CTRL_TYPE_AREA, V4L2_CTRL_TYPE_RECT, V4L2_CTRL_TYPE_HDR10_CLL_INFO, V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY, V4L2_CTRL_TYPE_H264_SPS, V4L2_CTRL_TYPE_H264_PPS, V4L2_CTRL_TYPE_H264_SCALING_MATRIX, V4L2_CTRL_TYPE_H264_SLICE_PARAMS, V4L2_CTRL_TYPE_H264_DECODE_PARAMS, V4L2_CTRL_TYPE_H264_PRED_WEIGHTS, V4L2_CTRL_TYPE_FWHT_PARAMS, V4L2_CTRL_TYPE_VP8_FRAME, V4L2_CTRL_TYPE_MPEG2_QUANTISATION, V4L2_CTRL_TYPE_MPEG2_SEQUENCE, V4L2_CTRL_TYPE_MPEG2_PICTURE, V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR, V4L2_CTRL_TYPE_VP9_FRAME, V4L2_CTRL_TYPE_HEVC_SPS, V4L2_CTRL_TYPE_HEVC_PPS, V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX, V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS, V4L2_CTRL_TYPE_AV1_SEQUENCE, V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY, V4L2_CTRL_TYPE_AV1_FRAME, V4L2_CTRL_TYPE_AV1_FILM_GRAIN
v4l2_priority = V4L2_PRIORITY_UNSET, V4L2_PRIORITY_BACKGROUND, V4L2_PRIORITY_INTERACTIVE, V4L2_PRIORITY_RECORD, V4L2_PRIORITY_DEFAULT
media_bus_fmt = MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB444_1X12, MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR565_2X8_BE, MEDIA_BUS_FMT_BGR565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB666_1X18, MEDIA_BUS_FMT_RBG888_1X24, MEDIA_BUS_FMT_RGB666_1X24_CPADHI, MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, MEDIA_BUS_FMT_BGR888_1X24, MEDIA_BUS_FMT_GBR888_1X24, MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_2X12_BE, MEDIA_BUS_FMT_RGB888_2X12_LE, MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, MEDIA_BUS_FMT_ARGB8888_1X32, MEDIA_BUS_FMT_RGB888_1X32_PADHI, MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_UV8_1X8, MEDIA_BUS_FMT_UYVY8_1_5X8, MEDIA_BUS_FMT_VYUY8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YVYU8_1_5X8, MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8, MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8, MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_UYVY10_2X10, MEDIA_BUS_FMT_VYUY10_2X10, MEDIA_BUS_FMT_YUYV10_2X10, MEDIA_BUS_FMT_YVYU10_2X10, MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_UYVY12_2X12, MEDIA_BUS_FMT_VYUY12_2X12, MEDIA_BUS_FMT_YUYV12_2X12, MEDIA_BUS_FMT_YVYU12_2X12, MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_YDYUYDYV8_1X16, MEDIA_BUS_FMT_UYVY10_1X20, MEDIA_BUS_FMT_VYUY10_1X20, MEDIA_BUS_FMT_YUYV10_1X20, MEDIA_BUS_FMT_YVYU10_1X20, MEDIA_BUS_FMT_VUY8_1X24, MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_UYVY12_1X24, MEDIA_BUS_FMT_VYUY12_1X24, MEDIA_BUS_FMT_YUYV12_1X24, MEDIA_BUS_FMT_YVYU12_1X24, MEDIA_BUS_FMT_YUV10_1X30, MEDIA_BUS_FMT_AYUV8_1X32, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_JPEG_1X8, MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8, MEDIA_BUS_FMT_AHSV8888_1X32
v4l2_pix_format_flags = V4L2_PIX_FMT_FLAG_PREMUL_ALPHA
v4l2_pix_format_pixelformat = V4L2_PIX_FMT_RGB332, V4L2_PIX_FMT_RGB444, V4L2_PIX_FMT_ARGB444, V4L2_PIX_FMT_XRGB444, V4L2_PIX_FMT_RGB555, V4L2_PIX_FMT_ARGB555, V4L2_PIX_FMT_XRGB555, V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_RGB555X, V4L2_PIX_FMT_ARGB555X, V4L2_PIX_FMT_XRGB555X, V4L2_PIX_FMT_RGB565X, V4L2_PIX_FMT_BGR666, V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_ABGR32, V4L2_PIX_FMT_XBGR32, V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_ARGB32, V4L2_PIX_FMT_XRGB32, V4L2_PIX_FMT_GREY, V4L2_PIX_FMT_Y4, V4L2_PIX_FMT_Y6, V4L2_PIX_FMT_Y10, V4L2_PIX_FMT_Y12, V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_Y16_BE, V4L2_PIX_FMT_Y10BPACK, V4L2_PIX_FMT_PAL8, V4L2_PIX_FMT_UV8, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_YYUV, V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_VYUY, V4L2_PIX_FMT_Y41P, V4L2_PIX_FMT_YUV444, V4L2_PIX_FMT_YUV555, V4L2_PIX_FMT_YUV565, V4L2_PIX_FMT_YUV32, V4L2_PIX_FMT_HI240, V4L2_PIX_FMT_NV12_16L16, V4L2_PIX_FMT_M420, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV21, V4L2_PIX_FMT_NV16, V4L2_PIX_FMT_NV61, V4L2_PIX_FMT_NV24, V4L2_PIX_FMT_NV42, V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_NV21M, V4L2_PIX_FMT_NV16M, V4L2_PIX_FMT_NV61M, V4L2_PIX_FMT_NV12MT, V4L2_PIX_FMT_NV12MT_16X16, V4L2_PIX_FMT_YUV410, V4L2_PIX_FMT_YVU410, V4L2_PIX_FMT_YUV411P, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420M, V4L2_PIX_FMT_YVU420M, V4L2_PIX_FMT_YUV422M, V4L2_PIX_FMT_YVU422M, V4L2_PIX_FMT_YUV444M, V4L2_PIX_FMT_YVU444M, V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SGBRG8, V4L2_PIX_FMT_SGRBG8, V4L2_PIX_FMT_SRGGB8, V4L2_PIX_FMT_SBGGR10, V4L2_PIX_FMT_SGBRG10, V4L2_PIX_FMT_SGRBG10, V4L2_PIX_FMT_SRGGB10, V4L2_PIX_FMT_SBGGR10P, V4L2_PIX_FMT_SGBRG10P, V4L2_PIX_FMT_SGRBG10P, V4L2_PIX_FMT_SRGGB10P, V4L2_PIX_FMT_SBGGR10ALAW8, V4L2_PIX_FMT_SGBRG10ALAW8, V4L2_PIX_FMT_SGRBG10ALAW8, V4L2_PIX_FMT_SRGGB10ALAW8, V4L2_PIX_FMT_SBGGR10DPCM8, V4L2_PIX_FMT_SGBRG10DPCM8, V4L2_PIX_FMT_SGRBG10DPCM8, V4L2_PIX_FMT_SRGGB10DPCM8, V4L2_PIX_FMT_SBGGR12, V4L2_PIX_FMT_SGBRG12, V4L2_PIX_FMT_SGRBG12, V4L2_PIX_FMT_SRGGB12, V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_DV, V4L2_PIX_FMT_MPEG, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_H264_NO_SC, V4L2_PIX_FMT_H264_MVC, V4L2_PIX_FMT_H263, V4L2_PIX_FMT_MPEG1, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_XVID, V4L2_PIX_FMT_VC1_ANNEX_G, V4L2_PIX_FMT_VC1_ANNEX_L, V4L2_PIX_FMT_VP8, V4L2_PIX_FMT_VP9, V4L2_PIX_FMT_HEVC, V4L2_PIX_FMT_CPIA1, V4L2_PIX_FMT_WNVA, V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_SN9C20X_I420, V4L2_PIX_FMT_PWC1, V4L2_PIX_FMT_PWC2, V4L2_PIX_FMT_ET61X251, V4L2_PIX_FMT_SPCA501, V4L2_PIX_FMT_SPCA505, V4L2_PIX_FMT_SPCA508, V4L2_PIX_FMT_SPCA561, V4L2_PIX_FMT_PAC207, V4L2_PIX_FMT_MR97310A, V4L2_PIX_FMT_JL2005BCD, V4L2_PIX_FMT_SN9C2028, V4L2_PIX_FMT_SQ905C, V4L2_PIX_FMT_PJPG, V4L2_PIX_FMT_OV511, V4L2_PIX_FMT_OV518, V4L2_PIX_FMT_STV0680, V4L2_PIX_FMT_TM6000, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_PIX_FMT_KONICA420, V4L2_PIX_FMT_JPGL, V4L2_PIX_FMT_SE401, V4L2_PIX_FMT_S5C_UYVY_JPG, V4L2_PIX_FMT_Y8I, V4L2_PIX_FMT_Y12I, V4L2_PIX_FMT_Z16
v4l2_meta_data_formats = V4L2_META_FMT_VSP1_HGO, V4L2_META_FMT_VSP1_HGT, V4L2_META_FMT_UVC, V4L2_META_FMT_D4XX, V4L2_META_FMT_UVC_MSXU_1_5, V4L2_META_FMT_VIVID, V4L2_META_FMT_RK_ISP1_PARAMS, V4L2_META_FMT_RK_ISP1_STAT_3A, V4L2_META_FMT_RK_ISP1_EXT_PARAMS, V4L2_META_FMT_C3ISP_PARAMS, V4L2_META_FMT_C3ISP_STATS, V4L2_META_FMT_RPI_BE_CFG, V4L2_META_FMT_RPI_FE_CFG, V4L2_META_FMT_RPI_FE_STATS, V4L2_META_FMT_MALI_C55_PARAMS, V4L2_META_FMT_MALI_C55_STATS, V4L2_META_FMT_GENERIC_8, V4L2_META_FMT_GENERIC_CSI2_10, V4L2_META_FMT_GENERIC_CSI2_12, V4L2_META_FMT_GENERIC_CSI2_14, V4L2_META_FMT_GENERIC_CSI2_16, V4L2_META_FMT_GENERIC_CSI2_20, V4L2_META_FMT_GENERIC_CSI2_24
v4l2_fmtdesc_flags = V4L2_FMT_FLAG_COMPRESSED, V4L2_FMT_FLAG_EMULATED, V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, V4L2_FMT_FLAG_DYN_RESOLUTION, V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL, V4L2_FMT_FLAG_CSC_COLORSPACE, V4L2_FMT_FLAG_CSC_XFER_FUNC, V4L2_FMT_FLAG_CSC_YCBCR_ENC, V4L2_FMT_FLAG_CSC_HSV_ENC, V4L2_FMT_FLAG_CSC_QUANTIZATION, V4L2_FMT_FLAG_META_LINE_BASED
v4l2_capability_capabilities = V4L2_CAP_VIDEO_CAPTURE, V4L2_CAP_VIDEO_OUTPUT, V4L2_CAP_VIDEO_OVERLAY, V4L2_CAP_VBI_CAPTURE, V4L2_CAP_VBI_OUTPUT, V4L2_CAP_SLICED_VBI_CAPTURE, V4L2_CAP_SLICED_VBI_OUTPUT, V4L2_CAP_RDS_CAPTURE, V4L2_CAP_VIDEO_OUTPUT_OVERLAY, V4L2_CAP_HW_FREQ_SEEK, V4L2_CAP_RDS_OUTPUT, V4L2_CAP_VIDEO_CAPTURE_MPLANE, V4L2_CAP_VIDEO_OUTPUT_MPLANE, V4L2_CAP_VIDEO_M2M_MPLANE, V4L2_CAP_VIDEO_M2M, V4L2_CAP_TUNER, V4L2_CAP_AUDIO, V4L2_CAP_RADIO, V4L2_CAP_MODULATOR, V4L2_CAP_SDR_CAPTURE, V4L2_CAP_EXT_PIX_FORMAT, V4L2_CAP_SDR_OUTPUT, V4L2_CAP_META_CAPTURE, V4L2_CAP_READWRITE, V4L2_CAP_EDID, V4L2_CAP_STREAMING, V4L2_CAP_META_OUTPUT, V4L2_CAP_TOUCH, V4L2_CAP_IO_MC, V4L2_CAP_DEVICE_CAPS
v4l2_framebuffer_capability = V4L2_FBUF_CAP_EXTERNOVERLAY, V4L2_FBUF_CAP_CHROMAKEY, V4L2_FBUF_CAP_LOCAL_ALPHA, V4L2_FBUF_CAP_GLOBAL_ALPHA, V4L2_FBUF_CAP_LOCAL_INV_ALPHA, V4L2_FBUF_CAP_SRC_CHROMAKEY
v4l2_framebuffer_flags = V4L2_FBUF_FLAG_PRIMARY, V4L2_FBUF_FLAG_OVERLAY, V4L2_FBUF_FLAG_CHROMAKEY, V4L2_FBUF_FLAG_LOCAL_ALPHA, V4L2_FBUF_FLAG_GLOBAL_ALPHA, V4L2_FBUF_FLAG_LOCAL_INV_ALPHA, V4L2_FBUF_FLAG_SRC_CHROMAKEY
v4l2_vbi_format_flags = V4L2_VBI_UNSYNC, V4L2_VBI_INTERLACED, V4L2_VBI_ITU_525_F1_START, V4L2_VBI_ITU_525_F2_START, V4L2_VBI_ITU_625_F1_START, V4L2_VBI_ITU_625_F2_START
v4l2_buffer_flags = V4L2_BUF_FLAG_MAPPED, V4L2_BUF_FLAG_QUEUED, V4L2_BUF_FLAG_DONE, V4L2_BUF_FLAG_KEYFRAME, V4L2_BUF_FLAG_PFRAME, V4L2_BUF_FLAG_BFRAME, V4L2_BUF_FLAG_ERROR, V4L2_BUF_FLAG_IN_REQUEST, V4L2_BUF_FLAG_TIMECODE, V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF, V4L2_BUF_FLAG_PREPARED, V4L2_BUF_FLAG_NO_CACHE_INVALIDATE, V4L2_BUF_FLAG_NO_CACHE_CLEAN, V4L2_BUF_FLAG_TIMESTAMP_MASK, V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN, V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC, V4L2_BUF_FLAG_TIMESTAMP_COPY, V4L2_BUF_FLAG_TSTAMP_SRC_MASK, V4L2_BUF_FLAG_TSTAMP_SRC_EOF, V4L2_BUF_FLAG_TSTAMP_SRC_SOE, V4L2_BUF_FLAG_LAST, V4L2_BUF_FLAG_REQUEST_FD
v4l2_timecode_type = V4L2_TC_TYPE_24FPS, V4L2_TC_TYPE_25FPS, V4L2_TC_TYPE_30FPS, V4L2_TC_TYPE_50FPS, V4L2_TC_TYPE_60FPS
v4l2_timecode_flags = V4L2_TC_FLAG_DROPFRAME, V4L2_TC_FLAG_COLORFRAME, V4L2_TC_USERBITS_field, V4L2_TC_USERBITS_USERDEFINED, V4L2_TC_USERBITS_8BITCHARS
v4l2_captureparm_cap = V4L2_CAP_TIMEPERFRAME
v4l2_captureparm_mode = V4L2_MODE_HIGHQUALITY
v4l2_tuner_capability = V4L2_TUNER_CAP_LOW, V4L2_TUNER_CAP_NORM, V4L2_TUNER_CAP_HWSEEK_BOUNDED, V4L2_TUNER_CAP_HWSEEK_WRAP, V4L2_TUNER_CAP_STEREO, V4L2_TUNER_CAP_LANG2, V4L2_TUNER_CAP_SAP, V4L2_TUNER_CAP_LANG1, V4L2_TUNER_CAP_RDS, V4L2_TUNER_CAP_RDS_BLOCK_IO, V4L2_TUNER_CAP_RDS_CONTROLS, V4L2_TUNER_CAP_FREQ_BANDS, V4L2_TUNER_CAP_HWSEEK_PROG_LIM, V4L2_TUNER_CAP_1HZ
v4l2_tuner_rxsubchans = V4L2_TUNER_SUB_MONO, V4L2_TUNER_SUB_STEREO, V4L2_TUNER_SUB_LANG2, V4L2_TUNER_SUB_SAP, V4L2_TUNER_SUB_LANG1, V4L2_TUNER_SUB_RDS
v4l2_tuner_audmode = V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO, V4L2_TUNER_MODE_LANG2, V4L2_TUNER_MODE_SAP, V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG1_LANG2
v4l2_audio_capability = V4L2_AUDCAP_STEREO, V4L2_AUDCAP_AVL
v4l2_audio_mode = V4L2_AUDMODE_AVL
v4l2_control_flags = V4L2_CTRL_FLAG_DISABLED, V4L2_CTRL_FLAG_GRABBED, V4L2_CTRL_FLAG_READ_ONLY, V4L2_CTRL_FLAG_UPDATE, V4L2_CTRL_FLAG_INACTIVE, V4L2_CTRL_FLAG_SLIDER, V4L2_CTRL_FLAG_WRITE_ONLY, V4L2_CTRL_FLAG_VOLATILE, V4L2_CTRL_FLAG_HAS_PAYLOAD, V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, V4L2_CTRL_FLAG_MODIFY_LAYOUT, V4L2_CTRL_FLAG_DYNAMIC_ARRAY, V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX, V4L2_CTRL_FLAG_NEXT_CTRL, V4L2_CTRL_FLAG_NEXT_COMPOUND
v4l2_ext_ctrl_class = V4L2_CTRL_CLASS_USER, V4L2_CTRL_CLASS_CODEC, V4L2_CTRL_CLASS_CAMERA, V4L2_CTRL_CLASS_FM_TX, V4L2_CTRL_CLASS_FLASH, V4L2_CTRL_CLASS_JPEG, V4L2_CTRL_CLASS_IMAGE_SOURCE, V4L2_CTRL_CLASS_IMAGE_PROC, V4L2_CTRL_CLASS_DV, V4L2_CTRL_CLASS_FM_RX, V4L2_CTRL_CLASS_RF_TUNER, V4L2_CTRL_CLASS_DETECT, V4L2_CTRL_ID_MASK, V4L2_CTRL_MAX_DIMS, V4L2_CTRL_WHICH_CUR_VAL, V4L2_CTRL_WHICH_DEF_VAL
#Comeback and add others from include/uapi/linux/videodev2.h#1617. Once after syz-extract able to detect with special chars
v4l2_ext_controls = V4L2_CID_USER_CLASS, V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST, V4L2_CID_SATURATION, V4L2_CID_HUE, V4L2_CID_AUDIO_VOLUME, V4L2_CID_AUDIO_BALANCE, V4L2_CID_AUDIO_BASS, V4L2_CID_AUDIO_TREBLE, V4L2_CID_AUDIO_MUTE, V4L2_CID_AUDIO_LOUDNESS, V4L2_CID_BLACK_LEVEL, V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CID_DO_WHITE_BALANCE, V4L2_CID_RED_BALANCE, V4L2_CID_BLUE_BALANCE, V4L2_CID_GAMMA, V4L2_CID_EXPOSURE, V4L2_CID_AUTOGAIN, V4L2_CID_GAIN, V4L2_CID_HFLIP, V4L2_CID_VFLIP, V4L2_CID_POWER_LINE_FREQUENCY, V4L2_CID_HUE_AUTO, V4L2_CID_WHITE_BALANCE_TEMPERATURE, V4L2_CID_SHARPNESS, V4L2_CID_BACKLIGHT_COMPENSATION, V4L2_CID_CHROMA_AGC, V4L2_CID_COLOR_KILLER, V4L2_CID_COLORFX, V4L2_CID_AUTOBRIGHTNESS, V4L2_CID_BAND_STOP_FILTER, V4L2_CID_ROTATE, V4L2_CID_BG_COLOR, V4L2_CID_CHROMA_GAIN, V4L2_CID_ILLUMINATORS_1, V4L2_CID_ILLUMINATORS_2, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, V4L2_CID_ALPHA_COMPONENT, V4L2_CID_COLORFX_CBCR, V4L2_CID_CODEC_CLASS, V4L2_CID_MPEG_STREAM_TYPE, V4L2_CID_MPEG_STREAM_PID_PMT, V4L2_CID_MPEG_STREAM_PID_AUDIO, V4L2_CID_MPEG_STREAM_PID_VIDEO, V4L2_CID_MPEG_STREAM_PID_PCR, V4L2_CID_MPEG_STREAM_PES_ID_AUDIO, V4L2_CID_MPEG_STREAM_PES_ID_VIDEO, V4L2_CID_MPEG_STREAM_VBI_FMT, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, V4L2_CID_MPEG_AUDIO_ENCODING, V4L2_CID_MPEG_AUDIO_L1_BITRATE, V4L2_CID_MPEG_AUDIO_L2_BITRATE, V4L2_CID_MPEG_AUDIO_L3_BITRATE, V4L2_CID_MPEG_AUDIO_MODE, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, V4L2_CID_MPEG_AUDIO_EMPHASIS, V4L2_CID_MPEG_AUDIO_CRC, V4L2_CID_MPEG_AUDIO_MUTE, V4L2_CID_MPEG_AUDIO_AAC_BITRATE, V4L2_CID_MPEG_AUDIO_AC3_BITRATE, V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK, V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK, V4L2_CID_MPEG_VIDEO_ENCODING, V4L2_CID_MPEG_VIDEO_ASPECT, V4L2_CID_MPEG_VIDEO_B_FRAMES, V4L2_CID_MPEG_VIDEO_GOP_SIZE, V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, V4L2_CID_MPEG_VIDEO_PULLDOWN, V4L2_CID_MPEG_VIDEO_BITRATE_MODE, V4L2_CID_MPEG_VIDEO_BITRATE, V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, V4L2_CID_MPEG_VIDEO_MUTE, V4L2_CID_MPEG_VIDEO_MUTE_YUV, V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, V4L2_CID_MPEG_VIDEO_HEADER_MODE, V4L2_CID_MPEG_VIDEO_MAX_REF_PIC, V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP, V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP, V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP, V4L2_CID_MPEG_VIDEO_H263_MIN_QP, V4L2_CID_MPEG_VIDEO_H263_MAX_QP, V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, V4L2_CID_MPEG_VIDEO_H264_MAX_QP, V4L2_CID_MPEG_VIDEO_H264_MIN_QP, V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT, V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH, V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC, V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING, V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0, V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE, V4L2_CID_MPEG_VIDEO_H264_FMO, V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE, V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP, V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION, V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE, V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH, V4L2_CID_MPEG_VIDEO_H264_ASO, V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER, V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP, V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP, V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP, V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, V4L2_CID_MPEG_VIDEO_MPEG4_QPEL, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, V4L2_CID_MPEG_VIDEO_VBV_SIZE, V4L2_CID_MPEG_VIDEO_DEC_PTS, V4L2_CID_MPEG_VIDEO_DEC_FRAME, V4L2_CID_MPEG_VIDEO_VBV_DELAY, V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE, V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE, V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS, V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4, V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES, V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL, V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS, V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD, V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL, V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, V4L2_CID_MPEG_VIDEO_VPX_MAX_QP, V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP, V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP, V4L2_CID_MPEG_VIDEO_VPX_PROFILE, V4L2_CID_CAMERA_CLASS, V4L2_CID_EXPOSURE_AUTO, V4L2_CID_EXPOSURE_ABSOLUTE, V4L2_CID_EXPOSURE_AUTO_PRIORITY, V4L2_CID_PAN_RELATIVE, V4L2_CID_TILT_RELATIVE, V4L2_CID_PAN_RESET, V4L2_CID_TILT_RESET, V4L2_CID_PAN_ABSOLUTE, V4L2_CID_TILT_ABSOLUTE, V4L2_CID_FOCUS_ABSOLUTE, V4L2_CID_FOCUS_RELATIVE, V4L2_CID_FOCUS_AUTO, V4L2_CID_ZOOM_ABSOLUTE, V4L2_CID_ZOOM_RELATIVE, V4L2_CID_ZOOM_CONTINUOUS, V4L2_CID_PRIVACY, V4L2_CID_IRIS_ABSOLUTE, V4L2_CID_IRIS_RELATIVE, V4L2_CID_AUTO_EXPOSURE_BIAS, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, V4L2_CID_WIDE_DYNAMIC_RANGE, V4L2_CID_IMAGE_STABILIZATION, V4L2_CID_ISO_SENSITIVITY, V4L2_CID_ISO_SENSITIVITY_AUTO, V4L2_CID_EXPOSURE_METERING, V4L2_CID_SCENE_MODE, V4L2_CID_3A_LOCK, V4L2_CID_AUTO_FOCUS_START, V4L2_CID_AUTO_FOCUS_STOP, V4L2_CID_AUTO_FOCUS_STATUS, V4L2_CID_AUTO_FOCUS_RANGE, V4L2_CID_PAN_SPEED, V4L2_CID_TILT_SPEED, V4L2_CID_FM_TX_CLASS, V4L2_CID_RDS_TX_DEVIATION, V4L2_CID_RDS_TX_PI, V4L2_CID_RDS_TX_PTY, V4L2_CID_RDS_TX_PS_NAME, V4L2_CID_RDS_TX_RADIO_TEXT, V4L2_CID_RDS_TX_MONO_STEREO, V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, V4L2_CID_RDS_TX_COMPRESSED, V4L2_CID_RDS_TX_DYNAMIC_PTY, V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, V4L2_CID_RDS_TX_MUSIC_SPEECH, V4L2_CID_RDS_TX_ALT_FREQS_ENABLE, V4L2_CID_RDS_TX_ALT_FREQS, V4L2_CID_AUDIO_LIMITER_ENABLED, V4L2_CID_AUDIO_LIMITER_RELEASE_TIME, V4L2_CID_AUDIO_LIMITER_DEVIATION, V4L2_CID_AUDIO_COMPRESSION_ENABLED, V4L2_CID_AUDIO_COMPRESSION_GAIN, V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME, V4L2_CID_PILOT_TONE_ENABLED, V4L2_CID_PILOT_TONE_DEVIATION, V4L2_CID_PILOT_TONE_FREQUENCY, V4L2_CID_TUNE_PREEMPHASIS, V4L2_CID_TUNE_POWER_LEVEL, V4L2_CID_TUNE_ANTENNA_CAPACITOR, V4L2_CID_FLASH_CLASS, V4L2_CID_FLASH_LED_MODE, V4L2_CID_FLASH_STROBE_SOURCE, V4L2_CID_FLASH_STROBE, V4L2_CID_FLASH_STROBE_STOP, V4L2_CID_FLASH_STROBE_STATUS, V4L2_CID_FLASH_TIMEOUT, V4L2_CID_FLASH_INTENSITY, V4L2_CID_FLASH_TORCH_INTENSITY, V4L2_CID_FLASH_INDICATOR_INTENSITY, V4L2_CID_FLASH_FAULT, V4L2_CID_FLASH_CHARGE, V4L2_CID_FLASH_READY, V4L2_CID_JPEG_CLASS, V4L2_CID_JPEG_CHROMA_SUBSAMPLING, V4L2_CID_JPEG_RESTART_INTERVAL, V4L2_CID_JPEG_COMPRESSION_QUALITY, V4L2_CID_JPEG_ACTIVE_MARKER, V4L2_CID_IMAGE_SOURCE_CLASS, V4L2_CID_VBLANK, V4L2_CID_HBLANK, V4L2_CID_ANALOGUE_GAIN, V4L2_CID_TEST_PATTERN_RED, V4L2_CID_TEST_PATTERN_GREENR, V4L2_CID_TEST_PATTERN_BLUE, V4L2_CID_TEST_PATTERN_GREENB, V4L2_CID_IMAGE_PROC_CLASS, V4L2_CID_LINK_FREQ, V4L2_CID_PIXEL_RATE, V4L2_CID_TEST_PATTERN, V4L2_CID_DV_CLASS, V4L2_CID_DV_TX_HOTPLUG, V4L2_CID_DV_TX_RXSENSE, V4L2_CID_DV_TX_EDID_PRESENT, V4L2_CID_DV_TX_MODE, V4L2_CID_DV_TX_RGB_RANGE, V4L2_CID_DV_TX_IT_CONTENT_TYPE, V4L2_CID_DV_RX_POWER_PRESENT, V4L2_CID_DV_RX_RGB_RANGE, V4L2_CID_DV_RX_IT_CONTENT_TYPE, V4L2_CID_FM_RX_CLASS, V4L2_CID_TUNE_DEEMPHASIS, V4L2_CID_RDS_RECEPTION, V4L2_CID_RF_TUNER_CLASS, V4L2_CID_RF_TUNER_RF_GAIN, V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, V4L2_CID_RF_TUNER_LNA_GAIN, V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, V4L2_CID_RF_TUNER_MIXER_GAIN, V4L2_CID_RF_TUNER_IF_GAIN_AUTO, V4L2_CID_RF_TUNER_IF_GAIN, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, V4L2_CID_RF_TUNER_BANDWIDTH, V4L2_CID_RF_TUNER_PLL_LOCK, V4L2_CID_RDS_RX_PTY, V4L2_CID_RDS_RX_PS_NAME, V4L2_CID_RDS_RX_RADIO_TEXT, V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, V4L2_CID_RDS_RX_MUSIC_SPEECH, V4L2_CID_DETECT_CLASS, V4L2_CID_DETECT_MD_MODE, V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, V4L2_CID_DETECT_MD_THRESHOLD_GRID, V4L2_CID_DETECT_MD_REGION_GRID
v4l2_frmsizetypes = V4L2_FRMSIZE_TYPE_DISCRETE, V4L2_FRMSIZE_TYPE_CONTINUOUS, V4L2_FRMSIZE_TYPE_STEPWISE
v4l2_frmivaltypes = V4L2_FRMIVAL_TYPE_DISCRETE, V4L2_FRMIVAL_TYPE_CONTINUOUS, V4L2_FRMIVAL_TYPE_STEPWISE
v4l2_enc_idx_flags = V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_B, V4L2_ENC_IDX_FRAME_MASK
v4l2_dbg_match_type = V4L2_CHIP_MATCH_BRIDGE, V4L2_CHIP_MATCH_SUBDEV, V4L2_CHIP_MATCH_I2C_DRIVER, V4L2_CHIP_MATCH_I2C_ADDR, V4L2_CHIP_MATCH_AC97
v4l2_frequency_band_modulation = V4L2_BAND_MODULATION_VSB, V4L2_BAND_MODULATION_FM, V4L2_BAND_MODULATION_AM
v4l2_dv_timings_type = V4L2_DV_BT_656_1120
v4l2_bt_timings_interlaced = V4L2_DV_PROGRESSIVE, V4L2_DV_INTERLACED
v4l2_bt_timings_polarities = V4L2_DV_VSYNC_POS_POL, V4L2_DV_HSYNC_POS_POL
v4l2_bt_timings_standards = V4L2_DV_BT_STD_CEA861, V4L2_DV_BT_STD_DMT, V4L2_DV_BT_STD_CVT, V4L2_DV_BT_STD_GTF, V4L2_DV_BT_STD_SDI
v4l2_bt_timings_flags = V4L2_DV_FL_REDUCED_BLANKING, V4L2_DV_FL_CAN_REDUCE_FPS, V4L2_DV_FL_REDUCED_FPS, V4L2_DV_FL_HALF_LINE, V4L2_DV_FL_IS_CE_VIDEO, V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE
v4l2_encoder_cmd_cmd = V4L2_ENC_CMD_START, V4L2_ENC_CMD_STOP, V4L2_ENC_CMD_PAUSE, V4L2_ENC_CMD_RESUME
v4l2_encoder_flags = V4L2_ENC_CMD_STOP_AT_GOP_END
v4l2_decoder_cmd_cmd = V4L2_DEC_CMD_START, V4L2_DEC_CMD_STOP, V4L2_DEC_CMD_PAUSE, V4L2_DEC_CMD_RESUME
v4l2_decoder_cmd_flags = V4L2_DEC_CMD_START_MUTE_AUDIO, V4L2_DEC_CMD_PAUSE_TO_BLACK, V4L2_DEC_CMD_STOP_TO_BLACK, V4L2_DEC_CMD_STOP_IMMEDIATELY
v4l2_decoder_cmd_format = V4L2_DEC_START_FMT_NONE, V4L2_DEC_START_FMT_GOP
v4l2_event_src_changes = V4L2_EVENT_SRC_CH_RESOLUTION
v4l2_event_type = V4L2_EVENT_ALL, V4L2_EVENT_VSYNC, V4L2_EVENT_EOS, V4L2_EVENT_CTRL, V4L2_EVENT_FRAME_SYNC, V4L2_EVENT_SOURCE_CHANGE, V4L2_EVENT_MOTION_DET, V4L2_EVENT_PRIVATE_START
v4l2_event_ctrl_changes = V4L2_EVENT_CTRL_CH_VALUE, V4L2_EVENT_CTRL_CH_FLAGS, V4L2_EVENT_CTRL_CH_RANGE
v4l2_event_motion_det_flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ
v4l2_event_subscription_flags = V4L2_EVENT_SUB_FL_SEND_INITIAL, V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK
v4l2_selection_target = V4L2_SEL_TGT_CROP, V4L2_SEL_TGT_CROP_DEFAULT, V4L2_SEL_TGT_CROP_BOUNDS, V4L2_SEL_TGT_NATIVE_SIZE, V4L2_SEL_TGT_COMPOSE, V4L2_SEL_TGT_COMPOSE_DEFAULT, V4L2_SEL_TGT_COMPOSE_BOUNDS, V4L2_SEL_TGT_COMPOSE_PADDED
v4l2_selection_flags = V4L2_SEL_FLAG_GE, V4L2_SEL_FLAG_LE, V4L2_SEL_FLAG_KEEP_CONFIG
v4l2_bt_timings_cap_capabilities = V4L2_DV_BT_CAP_INTERLACED, V4L2_DV_BT_CAP_PROGRESSIVE, V4L2_DV_BT_CAP_REDUCED_BLANKING, V4L2_DV_BT_CAP_CUSTOM
v4l2_dbg_chip_info_flags = V4L2_CHIP_FL_READABLE, V4L2_CHIP_FL_WRITABLE
v4l2_std_id = V4L2_STD_PAL_B, V4L2_STD_PAL_B1, V4L2_STD_PAL_G, V4L2_STD_PAL_H, V4L2_STD_PAL_I, V4L2_STD_PAL_D, V4L2_STD_PAL_D1, V4L2_STD_PAL_K, V4L2_STD_PAL_M, V4L2_STD_PAL_N, V4L2_STD_PAL_Nc, V4L2_STD_PAL_60, V4L2_STD_NTSC_M, V4L2_STD_NTSC_M_JP, V4L2_STD_NTSC_443, V4L2_STD_NTSC_M_KR, V4L2_STD_SECAM_B, V4L2_STD_SECAM_D, V4L2_STD_SECAM_G, V4L2_STD_SECAM_H, V4L2_STD_SECAM_K, V4L2_STD_SECAM_K1, V4L2_STD_SECAM_L, V4L2_STD_SECAM_LC, V4L2_STD_ATSC_8_VSB, V4L2_STD_ATSC_16_VSB, V4L2_STD_NTSC, V4L2_STD_SECAM_DK, V4L2_STD_SECAM, V4L2_STD_PAL_BG, V4L2_STD_PAL_DK, V4L2_STD_PAL, V4L2_STD_B, V4L2_STD_G, V4L2_STD_H, V4L2_STD_L, V4L2_STD_GH, V4L2_STD_DK, V4L2_STD_BG, V4L2_STD_MN, V4L2_STD_MTS, V4L2_STD_525_60, V4L2_STD_625_50, V4L2_STD_ATSC, V4L2_STD_UNKNOWN, V4L2_STD_ALL
v4l2_input_status = V4L2_IN_ST_NO_POWER, V4L2_IN_ST_NO_SIGNAL, V4L2_IN_ST_NO_COLOR, V4L2_IN_ST_HFLIP, V4L2_IN_ST_VFLIP, V4L2_IN_ST_NO_H_LOCK, V4L2_IN_ST_COLOR_KILL, V4L2_IN_ST_NO_V_LOCK, V4L2_IN_ST_NO_STD_LOCK, V4L2_IN_ST_NO_SYNC, V4L2_IN_ST_NO_EQU, V4L2_IN_ST_NO_CARRIER, V4L2_IN_ST_MACROVISION, V4L2_IN_ST_NO_ACCESS, V4L2_IN_ST_VTR
v4l2_input_type = V4L2_INPUT_TYPE_TUNER, V4L2_INPUT_TYPE_CAMERA, V4L2_INPUT_TYPE_TOUCH
v4l2_input_capabilities = V4L2_IN_CAP_DV_TIMINGS, V4L2_IN_CAP_CUSTOM_TIMINGS, V4L2_IN_CAP_STD, V4L2_IN_CAP_NATIVE_SIZE
v4l2_output_type = V4L2_OUTPUT_TYPE_MODULATOR, V4L2_OUTPUT_TYPE_ANALOG, V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY
v4l2_output_capabilities = V4L2_OUT_CAP_DV_TIMINGS, V4L2_OUT_CAP_CUSTOM_TIMINGS, V4L2_OUT_CAP_STD, V4L2_OUT_CAP_NATIVE_SIZE
v4l2_query_ext_ctrl = V4L2_CTRL_FLAG_NEXT_CTRL, V4L2_CTRL_FLAG_NEXT_COMPOUND
# These are actually defined in the newer kernel versions.
# But the newer kernel versions don't build with make extract.
# This can be removed once we can regenerate consts on at least v6.19-rc3.
define V4L2_META_FMT_MALI_C55_PARAMS 1345664323
define V4L2_META_FMT_MALI_C55_STATS 1395995971
]
|
| 180/2 |
2026/07/30 12:37 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 177497
output: 479
thoughts: 81
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience:
**Refactoring the Reproducer with Device-Specific Opens**
Right, the reproducer is currently using a generic open call. I see we have `syz_open_dev$video` and, presumably, a similar function for I2C devices, `syz_open_dev$I2C`. This looks like the right approach, much more precise than the current method. We need to leverage these device-specific system call wrappers instead of the broader, less targeted opens. This should offer us greater control over the device and, hopefully, lead to a cleaner and more reliable reproducer. Time to rewrite the reproducer to take advantage of these primitives. I expect this refinement will make the code more readable and the exploit more direct.
|
| 181/2 |
2026/07/30 12:38 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect$hid(3, 0, &AUTO, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video0\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video1\x00', 0, 0)
r3 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-0\x00', 0, 0)
r4 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-1\x00', 0, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-2\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-3\x00', 0, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 182/2 |
2026/07/30 12:38 |
llm |
crash-repro-finder-compressor |
0m
Model:
Reply: ### 1. Approaches Tried and Results
* **KASAN Report Analysis**:
* Analyzed slab-use-after-free read of size 8 at offset 264 (`0x108`) inside a `kmalloc-4k` object.
* Identified that the allocation/free stack traces in the report pointing to `nsim_dev_trap_skb_build` and `kobject_uevent_env` are reallocation noise (red herrings).
* Calculated exact struct offsets: `struct usb_device` has `struct device dev` at offset 176 bytes. `struct device` has `const struct device_type *type` at offset 88 bytes. Total offset of `parent->type` is `176 + 88 = 264` bytes (`0x108`), matching the KASAN report exactly.
* Confirmed the UAF occurs in `i2c_adapter_depth` when dereferencing `parent->type` where `parent` is `adapter->dev.parent` pointing to a freed `struct usb_device`.
* **Driver Code Auditing**:
* Audited USB drivers setting `adapter->dev.parent = &usb_device->dev` and deferring `i2c_del_adapter` on disconnect.
* Ruled out `cx231xx`, `dvb_usb`, `dvb_usb_v2`, and `pvrusb2` (which calls `pvr2_i2c_core_done` synchronously in `pvr2_hdw_disconnect`).
* Identified vulnerable drivers:
* `au0828`: Defers `au0828_usb_release` (which calls `au0828_i2c_unregister` -> `i2c_del_adapter`) to `au0828_usb_v4l2_release` if V4L2 is open during disconnect.
* `si4713` (`radio-usb-si4713`): Defers `i2c_del_adapter` to `usb_si4713_video_device_release` (called when the last reference to `v4l2_dev` is dropped, i.e., when `/dev/radioX` is closed). Does not call `usb_get_dev()` in `probe`, leaving `usb_device` unprotected.
* `go7007`: Defers `i2c_del_adapter` to `go7007_remove` (called via `v4l2_device_put` when `/dev/videoX` is closed).
* **Syzkaller Program Construction & Syntax Debugging**:
* Attempted to use `syz_usb_connect` with raw hex strings (`&AUTO="1201..."` or `&AUTO='\x12\x01...'`), which failed with `wrong string arg` because `syz_usb_connect` expects a `usb_device_descriptor` struct, not a string.
* Attempted to use `&(0x7f0000000000)=ANY=[...]` and `ANY=@ANYBLOB=[...]`, which failed with `wrong union arg for "array"` because `ANYBLOB` is not a valid union option or array type.
* Attempted to construct `usb_device_descriptor` manually, but hit `wrong array arg *prog.BufferType` due to complex nested struct/array definitions in `vusb.txt` (specifically `interfaces` array in `usb_config_descriptor`).
* Discovered `syz_usb_connect$hid` with `&AUTO` allows syzkaller to automatically generate a valid HID device descriptor.
* Discovered `syz_open_dev$I2C` and `syz_open_dev$radio` / `syz_open_dev$video` are the correct pseudo-syscalls to open `/dev/i2c-X` and `/dev/radioX` / `/dev/videoX` respectively, returning the correct resource types (`fd_i2c` and `fd_video`).
### 2. Current Hypotheses & Active Lines of Investigation
* **Deferred Cleanup Race via `si4713` or `au0828`**:
1. Emulate a USB device matching `si4713` (Vendor `0x10c4`, Product `0x8244`, Interface Class `USB_CLASS_HID`) or `au0828` (Vendor `0x2040`, Product `0x7200`).
2. Open the corresponding video/radio device (e.g., `/dev/radio0` or `/dev/video0`) to hold a reference to the driver context.
3. Open the corresponding I2C device (e.g., `/dev/i2c-0`).
4. Disconnect the USB device. The driver's `disconnect` callback runs but defers the unregistration of the I2C adapter because the video/radio device is still open.
5. The USB core frees the `struct usb_device`.
6. Perform an I2C transaction (e.g., `ioctl$I2C_SMBUS`) on the open I2C file descriptor. This triggers `i2c_adapter_depth` which dereferences `adapter->dev.parent->type` (offset 264 of the freed `usb_device`), causing the UAF.
### 3. Critical Code and Configuration Values
* **Vulnerable Code Path**:
```c
// drivers/i2c/i2c-core-base.c
unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
{
unsigned int depth = 0;
struct device *parent;
for (parent = adapter->dev.parent; parent; parent = parent->parent)
if (parent->type == &i2c_adapter_type) // UAF here: parent points to freed usb_device
depth++;
...
}
```
* **Struct Layout Offsets**:
* `struct usb_device` size: ~2251 bytes (fits in `kmalloc-4k`).
* `usb_device->dev` offset: 176 bytes.
* `device->type` offset: 88 bytes.
* Total offset of `usb_device->dev.type`: 264 bytes (`0x108`).
* **USB IDs & Classes**:
* `si4713`: Vendor `0x10c4`, Product `0x8244`, Interface Class `0x03` (`USB_CLASS_HID`).
* `au0828`: Vendor `0x2040`, Product `0x7200`.
* `go7007`: Vendor `0x0eb1`, Product `0x7007`.
* **Syzkaller API Definitions**:
* `syz_open_dev$I2C(dev ptr[in, string["/dev/i2c-#"]], id intptr, flags flags[open_flags]) fd_i2c`
* `syz_open_dev$radio(dev ptr[in, string["/dev/radio#"]], id proc[0, 4], flags const[O_RDWR]) fd_video`
* `syz_open_dev$video(dev ptr[in, string["/dev/video#"]], id intptr, flags flags[open_flags]) fd_video`
### 4. Potential Reasoning Loops / Repetitive Tool Calls
* Avoid manually constructing the `usb_device_descriptor` struct literal in the syzkaller program, as the parser is extremely strict and prone to `wrong array arg *prog.BufferType` errors due to nested `void` and `len` fields.
* Instead, use `syz_usb_connect$hid(3, 0, &AUTO, 0)` which lets syzkaller automatically generate a valid HID device descriptor, and rely on syzkaller's automatic USB ID patching to match `si4713` (`0x10c4:0x8244`).
Tokens:
input: 191091
output: 1903
thoughts: 2104
|
| 183/2 |
2026/07/30 12:38 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 21561
output: 22
thoughts: 39
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Investigating a Video Device Path in Syzkaller**
Right, `syz_open_dev$video`. That's pointing towards a video device, and it's expecting a specific path format: `/dev/video#\x00`. Specifically, the null-terminated string. Okay, good. That confirms the general structure I would expect, but I need to make sure I understand the precise implementation and any nuances in the driver.
Time to consult the definitive source for V4L2 device handling, `dev_video4linux.txt`. I need to review this to confirm expected behavior, permissions, and any potential gotchas with the device node names or the way it handles errors or invalid arguments. That's the place to look for any subtle details.
|
| 184/2 |
2026/07/30 12:38 |
tool |
read-description |
0m
Args: map[File:dev_video4linux.txt]
Results: map[Output:# Copyright 2018 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
include <linux/time.h>
include <linux/types.h>
include <uapi/asm/ioctl.h>
include <uapi/linux/fcntl.h>
include <uapi/linux/videodev2.h>
include <uapi/linux/v4l2-common.h>
include <uapi/linux/v4l2-subdev.h>
include <uapi/linux/v4l2-mediabus.h>
include <uapi/linux/media-bus-format.h>
include <uapi/linux/v4l2-controls.h>
include <uapi/linux/media.h>
resource fd_video[fd]
resource fd_v4l2_buffer[fd]
syz_open_dev$video(dev ptr[in, string["/dev/video#"]], id intptr, flags flags[open_flags]) fd_video
syz_open_dev$video4linux(dev ptr[in, string["/dev/v4l-subdev#"]], id intptr, flags flags[open_flags]) fd_video
# TODO: we now get wrong values for ioctl commands that involve v4l2_buffer and v4l2_event.
# Our definition uses 32-bit timespec, while kernel uses 64-bit timespec when __KERNEL__ is defined.
# Special support for CONFIG_VIDEO_VIMC/VIM2M/VIVID/VICODEC.
# Here we assume that all of them are enabled and the following arguments are passed on command line:
# vivid.n_devs=16 vivid.multiplanar=1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2
openat$vimc0(fd const[AT_FDCWD], file ptr[in, string["/dev/video0"]], flags const[O_RDWR], mode const[0]) fd_video
openat$vimc1(fd const[AT_FDCWD], file ptr[in, string["/dev/video1"]], flags const[O_RDWR], mode const[0]) fd_video
openat$vimc2(fd const[AT_FDCWD], file ptr[in, string["/dev/video2"]], flags const[O_RDWR], mode const[0]) fd_video
syz_open_dev$vivid(dev ptr[in, string["/dev/video#"]], id proc[3, 4], flags const[O_RDWR]) fd_video
openat$vicodec0(fd const[AT_FDCWD], file ptr[in, string["/dev/video36"]], flags const[O_RDWR], mode const[0]) fd_video
openat$vicodec1(fd const[AT_FDCWD], file ptr[in, string["/dev/video37"]], flags const[O_RDWR], mode const[0]) fd_video
# TODO: there are some complex rules as to what ioctl's are applicable to what devices
# (see determine_valid_ioctls in v4l2-dev.c). We don't have these rules described.
# Currently we just apply all ioctl's to all v4l devices.
syz_open_dev$swradio(dev ptr[in, string["/dev/swradio#"]], id proc[0, 2], flags const[O_RDWR]) fd_video
syz_open_dev$radio(dev ptr[in, string["/dev/radio#"]], id proc[0, 4], flags const[O_RDWR]) fd_video
syz_open_dev$vbi(dev ptr[in, string["/dev/vbi#"]], id proc[0, 4], flags const[O_RDWR]) fd_video
ioctl$VIDIOC_QUERYCAP(fd fd_video, cmd const[VIDIOC_QUERYCAP], arg ptr[out, v4l2_capability])
ioctl$VIDIOC_ENUM_FMT(fd fd_video, cmd const[VIDIOC_ENUM_FMT], arg ptr[inout, v4l2_fmtdesc[v4l2_buf_type]])
ioctl$VIDIOC_G_FMT(fd fd_video, cmd const[VIDIOC_G_FMT], arg ptr[inout, v4l2_format[v4l2_buf_type]])
ioctl$VIDIOC_S_FMT(fd fd_video, cmd const[VIDIOC_S_FMT], arg ptr[inout, v4l2_format[v4l2_buf_type]])
ioctl$VIDIOC_REQBUFS(fd fd_video, cmd const[VIDIOC_REQBUFS], arg ptr[inout, v4l2_requestbuffers[v4l2_buf_type]])
# This variant serves as fd_v4l2_buffer constructor.
# Potentially more ioctl can create fd_v4l2_buffer, but the kernel code is hard to understand.
ioctl$VIDIOC_QUERYBUF_DMABUF(fd fd_video, cmd const[VIDIOC_QUERYBUF], arg ptr[inout, v4l2_buffer[v4l2_buf_type, V4L2_MEMORY_DMABUF, fd_v4l2_buffer]])
ioctl$VIDIOC_QUERYBUF(fd fd_video, cmd const[VIDIOC_QUERYBUF], arg ptr[inout, v4l2_buffer_t[v4l2_buf_type]])
ioctl$VIDIOC_G_FBUF(fd fd_video, cmd const[VIDIOC_G_FBUF], arg ptr[inout, v4l2_framebuffer])
ioctl$VIDIOC_S_FBUF(fd fd_video, cmd const[VIDIOC_S_FBUF], arg ptr[in, v4l2_framebuffer])
ioctl$VIDIOC_OVERLAY(fd fd_video, cmd const[VIDIOC_OVERLAY], arg ptr[in, int32])
ioctl$VIDIOC_QBUF(fd fd_video, cmd const[VIDIOC_QBUF], arg ptr[inout, v4l2_buffer_t[v4l2_buf_type]])
ioctl$VIDIOC_EXPBUF(fd fd_video, cmd const[VIDIOC_EXPBUF], arg ptr[inout, v4l2_exportbuffer[v4l2_buf_type]])
ioctl$VIDIOC_DQBUF(fd fd_video, cmd const[VIDIOC_DQBUF], arg ptr[inout, v4l2_buffer_t[v4l2_buf_type]])
ioctl$VIDIOC_STREAMON(fd fd_video, cmd const[VIDIOC_STREAMON], arg ptr[in, int32])
ioctl$VIDIOC_STREAMOFF(fd fd_video, cmd const[VIDIOC_STREAMOFF], arg ptr[in, int32])
ioctl$VIDIOC_G_PARM(fd fd_video, cmd const[VIDIOC_G_PARM], arg ptr[inout, v4l2_streamparm])
ioctl$VIDIOC_S_PARM(fd fd_video, cmd const[VIDIOC_S_PARM], arg ptr[inout, v4l2_streamparm])
ioctl$VIDIOC_G_STD(fd fd_video, cmd const[VIDIOC_G_STD], arg ptr[out, v4l2_std_id])
ioctl$VIDIOC_S_STD(fd fd_video, cmd const[VIDIOC_S_STD], arg ptr[in, v4l2_std_id])
ioctl$VIDIOC_ENUMSTD(fd fd_video, cmd const[VIDIOC_ENUMSTD], arg ptr[inout, v4l2_standard])
ioctl$VIDIOC_ENUMINPUT(fd fd_video, cmd const[VIDIOC_ENUMINPUT], arg ptr[inout, v4l2_input])
ioctl$VIDIOC_G_CTRL(fd fd_video, cmd const[VIDIOC_G_CTRL], arg ptr[inout, v4l2_control])
ioctl$VIDIOC_S_CTRL(fd fd_video, cmd const[VIDIOC_S_CTRL], arg ptr[inout, v4l2_control])
ioctl$VIDIOC_G_TUNER(fd fd_video, cmd const[VIDIOC_G_TUNER], arg ptr[inout, v4l2_tuner])
ioctl$VIDIOC_S_TUNER(fd fd_video, cmd const[VIDIOC_S_TUNER], arg ptr[in, v4l2_tuner])
ioctl$VIDIOC_G_AUDIO(fd fd_video, cmd const[VIDIOC_G_AUDIO], arg ptr[out, v4l2_audio])
ioctl$VIDIOC_S_AUDIO(fd fd_video, cmd const[VIDIOC_S_AUDIO], arg ptr[in, v4l2_audio])
ioctl$VIDIOC_QUERYCTRL(fd fd_video, cmd const[VIDIOC_QUERYCTRL], arg ptr[inout, v4l2_queryctrl])
ioctl$VIDIOC_QUERYMENU(fd fd_video, cmd const[VIDIOC_QUERYMENU], arg ptr[inout, v4l2_querymenu])
ioctl$VIDIOC_G_INPUT(fd fd_video, cmd const[VIDIOC_G_INPUT], arg ptr[out, int32])
ioctl$VIDIOC_S_INPUT(fd fd_video, cmd const[VIDIOC_S_INPUT], arg ptr[inout, int32])
ioctl$VIDIOC_G_EDID(fd fd_video, cmd const[VIDIOC_G_EDID], arg ptr[inout, v4l2_edid])
ioctl$VIDIOC_S_EDID(fd fd_video, cmd const[VIDIOC_S_EDID], arg ptr[inout, v4l2_edid])
ioctl$VIDIOC_G_OUTPUT(fd fd_video, cmd const[VIDIOC_G_OUTPUT], arg ptr[out, int32])
ioctl$VIDIOC_S_OUTPUT(fd fd_video, cmd const[VIDIOC_S_OUTPUT], arg ptr[inout, int32])
ioctl$VIDIOC_ENUMOUTPUT(fd fd_video, cmd const[VIDIOC_ENUMOUTPUT], arg ptr[inout, v4l2_output])
ioctl$VIDIOC_G_AUDOUT(fd fd_video, cmd const[VIDIOC_G_AUDOUT], arg ptr[out, v4l2_audioout])
ioctl$VIDIOC_S_AUDOUT(fd fd_video, cmd const[VIDIOC_S_AUDOUT], arg ptr[in, v4l2_audioout])
ioctl$VIDIOC_G_MODULATOR(fd fd_video, cmd const[VIDIOC_G_MODULATOR], arg ptr[inout, v4l2_modulator])
ioctl$VIDIOC_S_MODULATOR(fd fd_video, cmd const[VIDIOC_S_MODULATOR], arg ptr[in, v4l2_modulator])
ioctl$VIDIOC_G_FREQUENCY(fd fd_video, cmd const[VIDIOC_G_FREQUENCY], arg ptr[inout, v4l2_frequency])
ioctl$VIDIOC_S_FREQUENCY(fd fd_video, cmd const[VIDIOC_S_FREQUENCY], arg ptr[in, v4l2_frequency])
ioctl$VIDIOC_CROPCAP(fd fd_video, cmd const[VIDIOC_CROPCAP], arg ptr[inout, v4l2_cropcap])
ioctl$VIDIOC_G_CROP(fd fd_video, cmd const[VIDIOC_G_CROP], arg ptr[inout, v4l2_crop])
ioctl$VIDIOC_S_CROP(fd fd_video, cmd const[VIDIOC_S_CROP], arg ptr[in, v4l2_crop])
ioctl$VIDIOC_G_JPEGCOMP(fd fd_video, cmd const[VIDIOC_G_JPEGCOMP], arg ptr[out, v4l2_jpegcompression])
ioctl$VIDIOC_S_JPEGCOMP(fd fd_video, cmd const[VIDIOC_S_JPEGCOMP], arg ptr[in, v4l2_jpegcompression])
ioctl$VIDIOC_QUERYSTD(fd fd_video, cmd const[VIDIOC_QUERYSTD], arg ptr[out, v4l2_std_id])
ioctl$VIDIOC_TRY_FMT(fd fd_video, cmd const[VIDIOC_TRY_FMT], arg ptr[inout, v4l2_format[v4l2_buf_type]])
ioctl$VIDIOC_ENUMAUDIO(fd fd_video, cmd const[VIDIOC_ENUMAUDIO], arg ptr[inout, v4l2_audio])
ioctl$VIDIOC_ENUMAUDOUT(fd fd_video, cmd const[VIDIOC_ENUMAUDOUT], arg ptr[inout, v4l2_audioout])
ioctl$VIDIOC_G_PRIORITY(fd fd_video, cmd const[VIDIOC_G_PRIORITY], arg flags[v4l2_priority])
ioctl$VIDIOC_S_PRIORITY(fd fd_video, cmd const[VIDIOC_S_PRIORITY], arg flags[v4l2_priority])
ioctl$VIDIOC_G_SLICED_VBI_CAP(fd fd_video, cmd const[VIDIOC_G_SLICED_VBI_CAP], arg ptr[inout, v4l2_sliced_vbi_cap])
ioctl$VIDIOC_LOG_STATUS(fd fd_video, cmd const[VIDIOC_LOG_STATUS], arg const[0])
ioctl$VIDIOC_G_EXT_CTRLS(fd fd_video, cmd const[VIDIOC_G_EXT_CTRLS], arg ptr[inout, v4l2_ext_controls])
ioctl$VIDIOC_S_EXT_CTRLS(fd fd_video, cmd const[VIDIOC_S_EXT_CTRLS], arg ptr[inout, v4l2_ext_controls])
ioctl$VIDIOC_TRY_EXT_CTRLS(fd fd_video, cmd const[VIDIOC_TRY_EXT_CTRLS], arg ptr[inout, v4l2_ext_controls])
ioctl$VIDIOC_ENUM_FRAMESIZES(fd fd_video, cmd const[VIDIOC_ENUM_FRAMESIZES], arg ptr[inout, v4l2_frmsizeenum])
ioctl$VIDIOC_ENUM_FRAMEINTERVALS(fd fd_video, cmd const[VIDIOC_ENUM_FRAMEINTERVALS], arg ptr[inout, v4l2_frmivalenum])
ioctl$VIDIOC_G_ENC_INDEX(fd fd_video, cmd const[VIDIOC_G_ENC_INDEX], arg ptr[out, v4l2_enc_idx])
ioctl$VIDIOC_ENCODER_CMD(fd fd_video, cmd const[VIDIOC_ENCODER_CMD], arg ptr[inout, v4l2_encoder_cmd])
ioctl$VIDIOC_TRY_ENCODER_CMD(fd fd_video, cmd const[VIDIOC_TRY_ENCODER_CMD], arg ptr[inout, v4l2_encoder_cmd])
ioctl$VIDIOC_DBG_S_REGISTER(fd fd_video, cmd const[VIDIOC_DBG_S_REGISTER], arg ptr[in, v4l2_dbg_register])
ioctl$VIDIOC_DBG_G_REGISTER(fd fd_video, cmd const[VIDIOC_DBG_G_REGISTER], arg ptr[inout, v4l2_dbg_register])
ioctl$VIDIOC_S_HW_FREQ_SEEK(fd fd_video, cmd const[VIDIOC_S_HW_FREQ_SEEK], arg ptr[in, v4l2_hw_freq_seek])
ioctl$VIDIOC_S_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_S_DV_TIMINGS], arg ptr[inout, v4l2_dv_timings])
ioctl$VIDIOC_G_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_G_DV_TIMINGS], arg ptr[inout, v4l2_dv_timings])
ioctl$VIDIOC_DQEVENT(fd fd_video, cmd const[VIDIOC_DQEVENT], arg ptr[out, v4l2_event])
ioctl$VIDIOC_SUBSCRIBE_EVENT(fd fd_video, cmd const[VIDIOC_SUBSCRIBE_EVENT], arg ptr[in, v4l2_event_subscription])
ioctl$VIDIOC_UNSUBSCRIBE_EVENT(fd fd_video, cmd const[VIDIOC_UNSUBSCRIBE_EVENT], arg ptr[in, v4l2_event_subscription])
ioctl$VIDIOC_CREATE_BUFS(fd fd_video, cmd const[VIDIOC_CREATE_BUFS], arg ptr[inout, v4l2_create_buffers[v4l2_buf_type]])
ioctl$VIDIOC_PREPARE_BUF(fd fd_video, cmd const[VIDIOC_PREPARE_BUF], arg ptr[inout, v4l2_buffer_t[v4l2_buf_type]])
ioctl$VIDIOC_G_SELECTION(fd fd_video, cmd const[VIDIOC_G_SELECTION], arg ptr[inout, v4l2_selection])
ioctl$VIDIOC_S_SELECTION(fd fd_video, cmd const[VIDIOC_S_SELECTION], arg ptr[inout, v4l2_selection])
ioctl$VIDIOC_DECODER_CMD(fd fd_video, cmd const[VIDIOC_DECODER_CMD], arg ptr[inout, v4l2_decoder_cmd])
ioctl$VIDIOC_TRY_DECODER_CMD(fd fd_video, cmd const[VIDIOC_TRY_DECODER_CMD], arg ptr[inout, v4l2_decoder_cmd])
ioctl$VIDIOC_ENUM_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_ENUM_DV_TIMINGS], arg ptr[inout, v4l2_enum_dv_timings])
ioctl$VIDIOC_QUERY_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_QUERY_DV_TIMINGS], arg ptr[out, v4l2_dv_timings])
ioctl$VIDIOC_DV_TIMINGS_CAP(fd fd_video, cmd const[VIDIOC_DV_TIMINGS_CAP], arg ptr[inout, v4l2_dv_timings_cap])
ioctl$VIDIOC_ENUM_FREQ_BANDS(fd fd_video, cmd const[VIDIOC_ENUM_FREQ_BANDS], arg ptr[inout, v4l2_frequency_band])
ioctl$VIDIOC_DBG_G_CHIP_INFO(fd fd_video, cmd const[VIDIOC_DBG_G_CHIP_INFO], arg ptr[inout, v4l2_dbg_chip_info])
ioctl$VIDIOC_QUERY_EXT_CTRL(fd fd_video, cmd const[VIDIOC_QUERY_EXT_CTRL], arg ptr[inout, v4l2_query_ext_ctrl])
ioctl$VIDIOC_SUBDEV_G_FMT(fd fd_video, cmd const[VIDIOC_SUBDEV_G_FMT], arg ptr[inout, v4l2_subdev_format])
ioctl$VIDIOC_SUBDEV_S_FMT(fd fd_video, cmd const[VIDIOC_SUBDEV_S_FMT], arg ptr[inout, v4l2_subdev_format])
ioctl$VIDIOC_SUBDEV_G_FRAME_INTERVAL(fd fd_video, cmd const[VIDIOC_SUBDEV_G_FRAME_INTERVAL], arg ptr[inout, v4l2_subdev_frame_interval])
ioctl$VIDIOC_SUBDEV_S_FRAME_INTERVAL(fd fd_video, cmd const[VIDIOC_SUBDEV_S_FRAME_INTERVAL], arg ptr[inout, v4l2_subdev_frame_interval])
ioctl$VIDIOC_SUBDEV_ENUM_MBUS_CODE(fd fd_video, cmd const[VIDIOC_SUBDEV_ENUM_MBUS_CODE], arg ptr[inout, v4l2_subdev_mbus_code_enum])
ioctl$VIDIOC_SUBDEV_ENUM_FRAME_SIZE(fd fd_video, cmd const[VIDIOC_SUBDEV_ENUM_FRAME_SIZE], arg ptr[inout, v4l2_subdev_frame_size_enum])
ioctl$VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL(fd fd_video, cmd const[VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL], arg ptr[inout, v4l2_subdev_frame_interval_enum])
ioctl$VIDIOC_SUBDEV_G_CROP(fd fd_video, cmd const[VIDIOC_SUBDEV_G_CROP], arg ptr[inout, v4l2_subdev_crop])
ioctl$VIDIOC_SUBDEV_S_CROP(fd fd_video, cmd const[VIDIOC_SUBDEV_S_CROP], arg ptr[inout, v4l2_subdev_crop])
ioctl$VIDIOC_SUBDEV_G_SELECTION(fd fd_video, cmd const[VIDIOC_SUBDEV_G_SELECTION], arg ptr[inout, v4l2_subdev_selection])
ioctl$VIDIOC_SUBDEV_S_SELECTION(fd fd_video, cmd const[VIDIOC_SUBDEV_S_SELECTION], arg ptr[inout, v4l2_subdev_selection])
ioctl$VIDIOC_SUBDEV_G_EDID(fd fd_video, cmd const[VIDIOC_SUBDEV_G_EDID], arg ptr[inout, v4l2_edid])
ioctl$VIDIOC_SUBDEV_S_EDID(fd fd_video, cmd const[VIDIOC_SUBDEV_S_EDID], arg ptr[inout, v4l2_edid])
ioctl$VIDIOC_SUBDEV_S_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_SUBDEV_S_DV_TIMINGS], arg ptr[inout, v4l2_dv_timings])
ioctl$VIDIOC_SUBDEV_G_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_SUBDEV_G_DV_TIMINGS], arg ptr[inout, v4l2_dv_timings])
ioctl$VIDIOC_SUBDEV_ENUM_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_SUBDEV_ENUM_DV_TIMINGS], arg ptr[inout, v4l2_enum_dv_timings])
ioctl$VIDIOC_SUBDEV_QUERY_DV_TIMINGS(fd fd_video, cmd const[VIDIOC_SUBDEV_QUERY_DV_TIMINGS], arg ptr[out, v4l2_dv_timings])
ioctl$VIDIOC_SUBDEV_DV_TIMINGS_CAP(fd fd_video, cmd const[VIDIOC_SUBDEV_DV_TIMINGS_CAP], arg ptr[inout, v4l2_dv_timings_cap])
# Generally we don't specify close on resources,
# but fd_v4l2_buffer is not used as input anywhere else (why is it needed?).
# So this is added to prevent compilation errors.
close$fd_v4l2_buffer(fd fd_v4l2_buffer)
v4l2_capability {
driver array[int8, 16]
card array[int8, 32]
bus_info array[int8, 32]
version int32
capabilities flags[v4l2_capability_capabilities, int32]
device_caps int32
reserved array[const[0, int32], 3]
}
type v4l2_fmtdesc[BUF_TYPE] {
index int32
type flags[BUF_TYPE, int32]
flags flags[v4l2_fmtdesc_flags, int32]
description array[int8, 32]
pixelformat flags[v4l2_pix_format_pixelformat, int32]
reserved array[const[0, int32], 4]
}
type v4l2_format[BUF_TYPE] {
type flags[BUF_TYPE, int32]
fmt v4l2_format_fmt
}
v4l2_format_fmt [
pix v4l2_pix_format
pix_mp v4l2_pix_format_mplane
win v4l2_window
vbi v4l2_vbi_format
sliced v4l2_sliced_vbi_format
sdr v4l2_sdr_format
meta v4l2_meta_format
raw_data array[int8, 200]
]
v4l2_pix_format {
width int32
height int32
pixelformat flags[v4l2_pix_format_pixelformat, int32]
field flags[v4l2_field, int32]
bytesperline int32
sizeimage int32
colorspace flags[v4l2_colorspace, int32]
priv int32
flags flags[v4l2_pix_format_flags, int32]
ycbcr_enc flags[v4l2_ycbcr_encoding, int32]
quantization flags[v4l2_quantization, int32]
xfer_func flags[v4l2_xfer_func, int32]
}
v4l2_pix_format_mplane {
width int32
height int32
pixelformat flags[v4l2_pix_format_pixelformat, int32]
field flags[v4l2_field, int32]
colorspace flags[v4l2_colorspace, int32]
plane_fmt array[v4l2_plane_pix_format, 8]
num_planes int8
flags int8
ycbcr_enc flags[v4l2_ycbcr_encoding, int8]
quantization flags[v4l2_quantization, int8]
xfer_func flags[v4l2_xfer_func, int8]
reserved array[const[0, int8], 7]
} [packed]
v4l2_plane_pix_format {
sizeimage int32
bytesperline int32
reserved array[const[0, int16], 6]
} [packed]
v4l2_window {
w v4l2_rect
field flags[v4l2_field, int32]
chromakey int32
clips ptr[inout, v4l2_clip]
clipcount int32
bitmap buffer[inout]
global_alpha int8
}
v4l2_rect {
left int32
top int32
width int32
height int32
}
v4l2_clip {
c v4l2_rect
next ptr[inout, v4l2_clip, opt]
}
v4l2_vbi_format {
sampling_rate int32
offset int32
samples_per_line int32
sample_format flags[v4l2_pix_format_pixelformat, int32]
start array[int32, 2]
count array[int32, 2]
flags flags[v4l2_vbi_format_flags, int32]
reserved array[const[0, int32], 2]
}
v4l2_sliced_vbi_format {
service_set int16
service_lines array[int16, 48]
io_size int32
reserved array[const[0, int32], 2]
}
v4l2_sdr_format {
pixelformat flags[v4l2_pix_format_pixelformat, int32]
buffersize int32
reserved array[const[0, int8], 24]
} [packed]
v4l2_meta_format {
dataformat flags[v4l2_meta_data_formats, int32]
buffersize int32[0:0x7fffffff]
width int32[0:65535]
height int32[0:65535]
bytesperline int32[0:0x7fffffff]
} [packed]
type v4l2_requestbuffers[BUF_TYPE] {
count int32
type flags[BUF_TYPE, int32]
memory flags[v4l2_memory, int32]
capabilities const[0, int32]
flags int8
reserved array[const[0, int8], 3]
}
type v4l2_buffer_t[BUF_TYPE] [
mmap v4l2_buffer[BUF_TYPE, V4L2_MEMORY_MMAP, intptr]
userptr v4l2_buffer[BUF_TYPE, V4L2_MEMORY_USERPTR, ptr[out, int8]]
overlay v4l2_buffer[BUF_TYPE, V4L2_MEMORY_OVERLAY, int32]
fd v4l2_buffer[BUF_TYPE, V4L2_MEMORY_DMABUF, fd_v4l2_buffer[opt]]
multiplanar_mmap v4l2_buffer[BUF_TYPE, V4L2_MEMORY_MMAP, ptr[inout, array[v4l2_plane[intptr], 2]]]
multiplanar_userptr v4l2_buffer[BUF_TYPE, V4L2_MEMORY_USERPTR, ptr[inout, array[v4l2_plane[ptr[out, int8]], 2]]]
multiplanar_overlay v4l2_buffer[BUF_TYPE, V4L2_MEMORY_OVERLAY, ptr[inout, array[v4l2_plane[int32], 2]]]
multiplanar_fd v4l2_buffer[BUF_TYPE, V4L2_MEMORY_DMABUF, ptr[inout, array[v4l2_plane[fd_v4l2_buffer[opt]], 2]]]
]
# TODO: The field directions needs to be defined. Recursively v4l2_plane, v4l2_plane_union needs checking.
type v4l2_buffer[BUF_TYPE, MEM_TYPE, ARG_TYPE] {
index int32
type flags[BUF_TYPE, int32]
bytesused len[type, int32]
flags flags[v4l2_buffer_flags, int32]
field int32
timestamp timeval
timecode v4l2_timecode
sequence int32
memory const[MEM_TYPE, int32]
m alignptr[ARG_TYPE] (out)
length int32
reserved2 const[0, int32]
request_fd fd_request[opt]
}
v4l2_timecode {
type flags[v4l2_timecode_type, int32]
flags flags[v4l2_timecode_flags, int32]
frames int8
seconds int8
minutes int8
hours int8
userbits array[int8, 4]
}
type v4l2_plane[ARG_TYPE] {
bytesused int32
length int32
m alignptr[ARG_TYPE]
data_offset int32
reserved array[const[0, int32], 11]
}
v4l2_framebuffer {
capability flags[v4l2_framebuffer_capability, int32]
flags flags[v4l2_framebuffer_flags, int32]
base buffer[inout]
fmt v4l2_framebuffer_union
}
v4l2_framebuffer_union {
width int32
height int32
pixelformat flags[v4l2_pix_format_pixelformat, int32]
field flags[v4l2_field, int32]
bytesperline int32
sizeimage int32
colorspace flags[v4l2_colorspace, int32]
priv int32
}
type v4l2_exportbuffer[BUF_TYPE] {
type flags[BUF_TYPE, int32]
index int32
plane int32
flags flags[pipe_flags, int32]
fd fd_dma_buf (out)
reserved array[const[0, int32], 11]
}
v4l2_streamparm {
type flags[v4l2_buf_type, int32]
parm v4l2_streamparm_union
}
v4l2_streamparm_union [
capture v4l2_captureparm
output v4l2_outputparm
raw_data array[int8, 200]
]
v4l2_captureparm {
capability flags[v4l2_captureparm_cap, int32]
capturemode flags[v4l2_captureparm_mode, int32]
timeperframe v4l2_fract
extendedmode int32
readbuffers int32
reserved array[const[0, int32], 4]
}
v4l2_fract {
numerator int32
denominator int32
}
v4l2_outputparm {
capability flags[v4l2_captureparm_cap, int32]
outputmode flags[v4l2_captureparm_mode, int32]
timeperframe v4l2_fract
extendedmode int32
writebuffers int32
reserved array[const[0, int32], 4]
}
v4l2_control {
id int32
value int32
}
v4l2_tuner {
index int32
name array[int8, 32]
type flags[v4l2_tuner_type, int32]
capability flags[v4l2_tuner_capability, int32]
rangelow int32
rangehigh int32
rxsubchans flags[v4l2_tuner_rxsubchans, int32]
audmode flags[v4l2_tuner_audmode, int32]
signal int32
afc int32
reserved array[const[0, int32], 4]
}
v4l2_audio {
index int32
name array[int8, 32]
capability flags[v4l2_audio_capability, int32]
mode flags[v4l2_audio_mode, int32]
reserved array[const[0, int32], 2]
}
v4l2_queryctrl {
id int32
type flags[v4l2_ctrl_type, int32]
name array[int8, 32]
minimum int32
maximum int32
step int32
default_value int32
flags flags[v4l2_control_flags, int32]
reserved array[const[0, int32], 2]
}
v4l2_querymenu {
id int32
index int32
union v4l2_querymenu_union
reserved const[0, int32]
} [packed]
v4l2_querymenu_union [
name array[int8, 32]
value int64
]
v4l2_edid {
pad const[0, int32]
start_block int32
blocks int32
reserved array[const[0, int32], 5]
edid ptr[inout, int8]
}
v4l2_audioout {
index int32
name array[int8, 32]
capability flags[v4l2_audio_capability, int32]
mode flags[v4l2_audio_mode, int32]
reserved array[const[0, int32], 2]
}
v4l2_modulator {
index int32
name array[int8, 32]
capability flags[v4l2_tuner_capability, int32]
rangelow int32
rangehigh int32
txsubchans flags[v4l2_tuner_rxsubchans, int32]
type flags[v4l2_tuner_type, int32]
reserved array[const[0, int32], 3]
}
v4l2_frequency {
tuner int32
type flags[v4l2_tuner_type, int32]
frequency int32
reserved array[const[0, int32], 8]
}
v4l2_cropcap {
type flags[v4l2_buf_type, int32]
bounds v4l2_rect
defrect v4l2_rect
pixelaspect v4l2_fract
}
v4l2_crop {
type flags[v4l2_buf_type, int32]
c v4l2_rect
}
v4l2_jpegcompression {
quality int32
APPn int32[0:15]
APP_len int32[0:60]
APP_data array[int8, 60]
COM_len int32[0:60]
COM_data array[int8, 60]
jpeg_markers flags[v4l2_jpeg_markers, int32]
}
v4l2_sliced_vbi_cap {
service_set int16
service_lines array[int16, 48]
type flags[v4l2_buf_type, int32]
reserved array[const[0, int32], 3]
}
v4l2_ext_controls {
ctrl_class flags[v4l2_ext_ctrl_class, int32]
count int32
error_idx int32
request_fd fd_request[opt] (in)
reserved const[0, int32]
controls ptr[inout, v4l2_ext_control]
}
v4l2_ext_control {
id flags[v4l2_ext_controls, int32]
size int32
reserved2 array[const[0, int32], 1]
union v4l2_ext_u
} [packed]
v4l2_ext_u [
value int32
value64 int64
string ptr[inout, int8]
p_u8 ptr[inout, int8]
p_u16 ptr[inout, int16]
p_u32 ptr[inout, int32]
ptr intptr
]
v4l2_frmsizeenum {
index int32
pixel_format flags[v4l2_pix_format_pixelformat, int32]
type flags[v4l2_frmsizetypes, int32]
union v4l2_frmsizeenum_union
reserved array[const[0, int32], 2]
}
v4l2_frmsizeenum_union [
discrete v4l2_frmsize_discrete
stepwise v4l2_frmsize_stepwise
]
v4l2_frmsize_discrete {
width int32
height int32
}
v4l2_frmsize_stepwise {
min_width int32
max_width int32
step_width int32
min_height int32
max_height int32
step_height int32
}
v4l2_frmivalenum {
index int32
pixel_format flags[v4l2_pix_format_pixelformat, int32]
width int32
height int32
type flags[v4l2_frmivaltypes, int32]
union v4l2_frmivalenum_union
reserved array[const[0, int32], 2]
}
v4l2_frmivalenum_union [
discrete v4l2_fract
stepwise v4l2_frmival_stepwise
]
v4l2_frmival_stepwise {
min v4l2_fract
max v4l2_fract
step v4l2_fract
}
v4l2_enc_idx {
entries int32
entries_cap int32
reserved array[const[0, int32], 4]
entry array[v4l2_enc_idx_entry, 64]
}
v4l2_enc_idx_entry {
offset int64
pts int64
length int32
flags flags[v4l2_enc_idx_flags, int32]
reserved array[const[0, int32], 2]
}
v4l2_dbg_register {
match v4l2_dbg_match
size bytesize[reg, int32]
reg int64
val int64
} [packed]
v4l2_dbg_match {
type flags[v4l2_dbg_match_type, int32]
union v4l2_dbg_match_union
} [packed]
v4l2_dbg_match_union [
addr int32
name array[int8, 32]
]
v4l2_hw_freq_seek {
tuner int32
type flags[v4l2_tuner_type, int32]
seek_upward int32
wrap_around int32
spacing int32
rangelow int32
rangehigh int32
reserved array[const[0, int32], 5]
}
v4l2_dv_timings {
type flags[v4l2_dv_timings_type, int32]
union v4l2_dv_timings_union
} [packed]
v4l2_dv_timings_union [
bt v4l2_bt_timings
reserved array[const[0, int32], 32]
]
v4l2_bt_timings {
width int32
height int32
interlaced flags[v4l2_bt_timings_interlaced, int32]
polarities flags[v4l2_bt_timings_polarities, int32]
pixelclock int64
hfrontporch int32
hsync int32
hbackporch int32
vfrontporch int32
vsync int32
vbackporch int32
il_vfrontporch int32
il_vsync int32
il_vbackporch int32
standards flags[v4l2_bt_timings_standards, int32]
flags flags[v4l2_bt_timings_flags, int32]
picture_aspect v4l2_fract
cea861_vic int8
hdmi_vic int8
reserved array[const[0, int8], 46]
} [packed]
v4l2_encoder_cmd {
cmd flags[v4l2_encoder_cmd_cmd, int32]
flags flags[v4l2_encoder_flags, int32]
data array[int32, 8]
}
v4l2_event {
type flags[v4l2_event_type, int32]
u v4l2_event_union
pending int32
sequence int32
timestamp timespec
id int32
reserved array[const[0, int32], 8]
}
v4l2_event_union [
vsync v4l2_event_vsync
ctrl v4l2_event_ctrl
frame_sync v4l2_event_frame_sync
src_change v4l2_event_src_change
motion_det v4l2_event_motion_det
data array[int8, 64]
]
v4l2_event_vsync {
field flags[v4l2_field_1, int8]
} [packed]
v4l2_event_ctrl {
changes flags[v4l2_event_ctrl_changes, int32]
type flags[v4l2_ctrl_type, int32]
u v4l2_event_ctrl_union
flags int32
minimum int32
maximum int32
step int32
default_value int32
}
v4l2_event_ctrl_union [
value int32
value64 int64
]
v4l2_event_frame_sync {
frame_sequence int32
}
v4l2_event_src_change {
changes flags[v4l2_event_src_changes, int32]
}
v4l2_event_motion_det {
flags flags[v4l2_event_motion_det_flags, int32]
frame_sequence int32
region_mask int32
}
v4l2_event_subscription {
type flags[v4l2_event_type, int32]
id int32
flags flags[v4l2_event_subscription_flags, int32]
reserved array[const[0, int32], 5]
}
type v4l2_create_buffers[BUF_TYPE] {
index int32
count int32
memory flags[v4l2_memory, int32]
format v4l2_format[BUF_TYPE]
capabilities int32
reserved array[const[0, int32], 7]
}
v4l2_selection {
type flags[v4l2_buf_type_1, int32]
target flags[v4l2_selection_target, int32]
flags flags[v4l2_selection_flags, int32]
r v4l2_rect
reserved array[const[0, int32], 9]
}
v4l2_decoder_cmd {
cmd flags[v4l2_decoder_cmd_cmd, int32]
flags flags[v4l2_decoder_cmd_flags, int32]
u v4l2_decoder_cmd_u
}
v4l2_decoder_cmd_u [
stop_pts int64
start v4l2_decoder_cmd_start
raw_data array[int32, 16]
]
v4l2_decoder_cmd_start {
speed int32
format flags[v4l2_decoder_cmd_format, int32]
}
v4l2_enum_dv_timings {
index int32
pad const[0, int32]
reserved array[const[0, int32], 2]
timings v4l2_dv_timings
}
v4l2_dv_timings_cap {
type flags[v4l2_dv_timings_type, int32]
pad const[0, int32]
reserved array[const[0, int32], 2]
u v4l2_dv_timings_cap_u
}
v4l2_dv_timings_cap_u [
bt v4l2_bt_timings_cap
raw_data array[int32, 32]
]
v4l2_bt_timings_cap {
min_width int32
max_width int32
min_height int32
max_height int32
min_pixelclock int64
max_pixelclock int64
standards flags[v4l2_bt_timings_standards, int32]
capabilities flags[v4l2_bt_timings_cap_capabilities, int32]
reserved array[const[0, int32], 16]
} [packed]
v4l2_frequency_band {
tuner int32
type flags[v4l2_tuner_type, int32]
index int32
capability flags[v4l2_tuner_capability, int32]
rangelow int32
rangehigh int32
modulation flags[v4l2_frequency_band_modulation, int32]
reserved array[const[0, int32], 9]
}
v4l2_dbg_chip_info {
match v4l2_dbg_match
name array[int8, 32]
flags flags[v4l2_dbg_chip_info_flags, int32]
reserved array[const[0, int32], 32]
} [packed]
v4l2_query_ext_ctrl {
id flags[v4l2_query_ext_ctrl, int32]
type flags[v4l2_ctrl_type, int32]
name array[int8, 32]
minimum int64
maximum int64
step int64
default_value int64
flags int32
elem_size int32
elems int32
nr_of_dims int32
dims array[int32, 4]
reserved array[const[0, int32], 32]
}
type v4l2_std_id flags[v4l2_std_id, int64]
v4l2_standard {
index int32
id v4l2_std_id
name array[int8, 24]
frameperiod v4l2_fract
framelines int32
reserved array[const[0, int32], 4]
}
v4l2_input {
index int32
name array[int8, 32]
type flags[v4l2_input_type, int32]
audioset int32
tuner flags[v4l2_tuner_type, int32]
std v4l2_std_id
status flags[v4l2_input_status, int32]
capabilities flags[v4l2_input_capabilities, int32]
reserved array[const[0, int32], 3]
}
v4l2_output {
index int32
name array[int8, 32]
type flags[v4l2_output_type, int32]
audioset int32
modulator int32
std v4l2_std_id
capabilities flags[v4l2_output_capabilities, int32]
reserved array[const[0, int32], 3]
}
v4l2_subdev_format {
which flags[v4l2_subdev_format_whence, int32]
pad const[0, int32]
format v4l2_mbus_framefmt
reserved array[const[0, int32], 8]
}
v4l2_mbus_framefmt {
width int32
height int32
code flags[media_bus_fmt, int32]
field flags[v4l2_field, int32]
colorspace flags[v4l2_colorspace, int32]
ycbcr_enc flags[v4l2_ycbcr_encoding, int16]
quantization flags[v4l2_quantization, int16]
xfer_func flags[v4l2_xfer_func, int16]
reserved array[const[0, int16], 11]
}
v4l2_subdev_frame_interval {
pad const[0, int32]
interval v4l2_fract
reserved array[const[0, int32], 9]
}
v4l2_subdev_mbus_code_enum {
pad const[0, int32]
index int32
code flags[media_bus_fmt, int32]
which flags[v4l2_subdev_format_whence, int32]
reserved array[const[0, int32], 8]
}
v4l2_subdev_frame_size_enum {
index int32
pad const[0, int32]
code flags[media_bus_fmt, int32]
min_width int32
max_width int32
min_height int32
max_height int32
which flags[v4l2_subdev_format_whence, int32]
reserved array[const[0, int32], 8]
}
v4l2_subdev_frame_interval_enum {
index int32
pad const[0, int32]
code flags[media_bus_fmt, int32]
width int32
height int32
interval v4l2_fract
which flags[v4l2_subdev_format_whence, int32]
reserved array[const[0, int32], 8]
}
v4l2_subdev_crop {
which flags[v4l2_subdev_format_whence, int32]
pad const[0, int32]
rect v4l2_rect
reserved array[const[0, int32], 8]
}
v4l2_subdev_selection {
which flags[v4l2_subdev_format_whence, int32]
pad const[0, int32]
target flags[v4l2_selection_target, int32]
flags flags[v4l2_selection_flags, int32]
r v4l2_rect
reserved array[const[0, int32], 8]
}
v4l2_jpeg_markers = V4L2_JPEG_MARKER_DHT, V4L2_JPEG_MARKER_DQT, V4L2_JPEG_MARKER_DRI, V4L2_JPEG_MARKER_COM, V4L2_JPEG_MARKER_APP
v4l2_subdev_format_whence = V4L2_SUBDEV_FORMAT_TRY, V4L2_SUBDEV_FORMAT_ACTIVE
v4l2_buf_type_1 = V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OVERLAY, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_BUF_TYPE_VBI_OUTPUT, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, V4L2_BUF_TYPE_SDR_CAPTURE, V4L2_BUF_TYPE_SDR_OUTPUT, V4L2_BUF_TYPE_META_CAPTURE, V4L2_BUF_TYPE_META_OUTPUT
v4l2_field_1 = V4L2_FIELD_ANY, V4L2_FIELD_NONE, V4L2_FIELD_TOP, V4L2_FIELD_BOTTOM
v4l2_field = V4L2_FIELD_INTERLACED, V4L2_FIELD_SEQ_TB, V4L2_FIELD_SEQ_BT, V4L2_FIELD_ALTERNATE, V4L2_FIELD_INTERLACED_TB, V4L2_FIELD_INTERLACED_BT, v4l2_field_1
v4l2_colorspace = V4L2_COLORSPACE_DEFAULT, V4L2_COLORSPACE_SMPTE170M, V4L2_COLORSPACE_SMPTE240M, V4L2_COLORSPACE_REC709, V4L2_COLORSPACE_BT878, V4L2_COLORSPACE_470_SYSTEM_M, V4L2_COLORSPACE_470_SYSTEM_BG, V4L2_COLORSPACE_JPEG, V4L2_COLORSPACE_SRGB, V4L2_COLORSPACE_OPRGB, V4L2_COLORSPACE_BT2020, V4L2_COLORSPACE_RAW, V4L2_COLORSPACE_DCI_P3
v4l2_ycbcr_encoding = V4L2_YCBCR_ENC_DEFAULT, V4L2_YCBCR_ENC_601, V4L2_YCBCR_ENC_709, V4L2_YCBCR_ENC_XV601, V4L2_YCBCR_ENC_XV709, V4L2_YCBCR_ENC_BT2020, V4L2_YCBCR_ENC_BT2020_CONST_LUM, V4L2_YCBCR_ENC_SMPTE240M
v4l2_quantization = V4L2_QUANTIZATION_DEFAULT, V4L2_QUANTIZATION_FULL_RANGE, V4L2_QUANTIZATION_LIM_RANGE
v4l2_xfer_func = V4L2_XFER_FUNC_DEFAULT, V4L2_XFER_FUNC_709, V4L2_XFER_FUNC_SRGB, V4L2_XFER_FUNC_OPRGB, V4L2_XFER_FUNC_SMPTE240M, V4L2_XFER_FUNC_NONE, V4L2_XFER_FUNC_DCI_P3, V4L2_XFER_FUNC_SMPTE2084
v4l2_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, v4l2_buf_type_1
v4l2_memory = V4L2_MEMORY_MMAP, V4L2_MEMORY_USERPTR, V4L2_MEMORY_OVERLAY, V4L2_MEMORY_DMABUF
v4l2_tuner_type = V4L2_TUNER_RADIO, V4L2_TUNER_ANALOG_TV, V4L2_TUNER_DIGITAL_TV, V4L2_TUNER_SDR, V4L2_TUNER_RF
v4l2_ctrl_type = V4L2_CTRL_TYPE_INTEGER, V4L2_CTRL_TYPE_BOOLEAN, V4L2_CTRL_TYPE_MENU, V4L2_CTRL_TYPE_BUTTON, V4L2_CTRL_TYPE_INTEGER64, V4L2_CTRL_TYPE_CTRL_CLASS, V4L2_CTRL_TYPE_STRING, V4L2_CTRL_TYPE_BITMASK, V4L2_CTRL_TYPE_INTEGER_MENU, V4L2_CTRL_COMPOUND_TYPES, V4L2_CTRL_TYPE_U8, V4L2_CTRL_TYPE_U16, V4L2_CTRL_TYPE_U32, V4L2_CTRL_TYPE_AREA, V4L2_CTRL_TYPE_RECT, V4L2_CTRL_TYPE_HDR10_CLL_INFO, V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY, V4L2_CTRL_TYPE_H264_SPS, V4L2_CTRL_TYPE_H264_PPS, V4L2_CTRL_TYPE_H264_SCALING_MATRIX, V4L2_CTRL_TYPE_H264_SLICE_PARAMS, V4L2_CTRL_TYPE_H264_DECODE_PARAMS, V4L2_CTRL_TYPE_H264_PRED_WEIGHTS, V4L2_CTRL_TYPE_FWHT_PARAMS, V4L2_CTRL_TYPE_VP8_FRAME, V4L2_CTRL_TYPE_MPEG2_QUANTISATION, V4L2_CTRL_TYPE_MPEG2_SEQUENCE, V4L2_CTRL_TYPE_MPEG2_PICTURE, V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR, V4L2_CTRL_TYPE_VP9_FRAME, V4L2_CTRL_TYPE_HEVC_SPS, V4L2_CTRL_TYPE_HEVC_PPS, V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX, V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS, V4L2_CTRL_TYPE_AV1_SEQUENCE, V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY, V4L2_CTRL_TYPE_AV1_FRAME, V4L2_CTRL_TYPE_AV1_FILM_GRAIN
v4l2_priority = V4L2_PRIORITY_UNSET, V4L2_PRIORITY_BACKGROUND, V4L2_PRIORITY_INTERACTIVE, V4L2_PRIORITY_RECORD, V4L2_PRIORITY_DEFAULT
media_bus_fmt = MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB444_1X12, MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR565_2X8_BE, MEDIA_BUS_FMT_BGR565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB666_1X18, MEDIA_BUS_FMT_RBG888_1X24, MEDIA_BUS_FMT_RGB666_1X24_CPADHI, MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, MEDIA_BUS_FMT_BGR888_1X24, MEDIA_BUS_FMT_GBR888_1X24, MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_2X12_BE, MEDIA_BUS_FMT_RGB888_2X12_LE, MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, MEDIA_BUS_FMT_ARGB8888_1X32, MEDIA_BUS_FMT_RGB888_1X32_PADHI, MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_UV8_1X8, MEDIA_BUS_FMT_UYVY8_1_5X8, MEDIA_BUS_FMT_VYUY8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YVYU8_1_5X8, MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8, MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8, MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_UYVY10_2X10, MEDIA_BUS_FMT_VYUY10_2X10, MEDIA_BUS_FMT_YUYV10_2X10, MEDIA_BUS_FMT_YVYU10_2X10, MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_UYVY12_2X12, MEDIA_BUS_FMT_VYUY12_2X12, MEDIA_BUS_FMT_YUYV12_2X12, MEDIA_BUS_FMT_YVYU12_2X12, MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_YDYUYDYV8_1X16, MEDIA_BUS_FMT_UYVY10_1X20, MEDIA_BUS_FMT_VYUY10_1X20, MEDIA_BUS_FMT_YUYV10_1X20, MEDIA_BUS_FMT_YVYU10_1X20, MEDIA_BUS_FMT_VUY8_1X24, MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_UYVY12_1X24, MEDIA_BUS_FMT_VYUY12_1X24, MEDIA_BUS_FMT_YUYV12_1X24, MEDIA_BUS_FMT_YVYU12_1X24, MEDIA_BUS_FMT_YUV10_1X30, MEDIA_BUS_FMT_AYUV8_1X32, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_JPEG_1X8, MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8, MEDIA_BUS_FMT_AHSV8888_1X32
v4l2_pix_format_flags = V4L2_PIX_FMT_FLAG_PREMUL_ALPHA
v4l2_pix_format_pixelformat = V4L2_PIX_FMT_RGB332, V4L2_PIX_FMT_RGB444, V4L2_PIX_FMT_ARGB444, V4L2_PIX_FMT_XRGB444, V4L2_PIX_FMT_RGB555, V4L2_PIX_FMT_ARGB555, V4L2_PIX_FMT_XRGB555, V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_RGB555X, V4L2_PIX_FMT_ARGB555X, V4L2_PIX_FMT_XRGB555X, V4L2_PIX_FMT_RGB565X, V4L2_PIX_FMT_BGR666, V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_ABGR32, V4L2_PIX_FMT_XBGR32, V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_ARGB32, V4L2_PIX_FMT_XRGB32, V4L2_PIX_FMT_GREY, V4L2_PIX_FMT_Y4, V4L2_PIX_FMT_Y6, V4L2_PIX_FMT_Y10, V4L2_PIX_FMT_Y12, V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_Y16_BE, V4L2_PIX_FMT_Y10BPACK, V4L2_PIX_FMT_PAL8, V4L2_PIX_FMT_UV8, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_YYUV, V4L2_PIX_FMT_YVYU, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_VYUY, V4L2_PIX_FMT_Y41P, V4L2_PIX_FMT_YUV444, V4L2_PIX_FMT_YUV555, V4L2_PIX_FMT_YUV565, V4L2_PIX_FMT_YUV32, V4L2_PIX_FMT_HI240, V4L2_PIX_FMT_NV12_16L16, V4L2_PIX_FMT_M420, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV21, V4L2_PIX_FMT_NV16, V4L2_PIX_FMT_NV61, V4L2_PIX_FMT_NV24, V4L2_PIX_FMT_NV42, V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_NV21M, V4L2_PIX_FMT_NV16M, V4L2_PIX_FMT_NV61M, V4L2_PIX_FMT_NV12MT, V4L2_PIX_FMT_NV12MT_16X16, V4L2_PIX_FMT_YUV410, V4L2_PIX_FMT_YVU410, V4L2_PIX_FMT_YUV411P, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420M, V4L2_PIX_FMT_YVU420M, V4L2_PIX_FMT_YUV422M, V4L2_PIX_FMT_YVU422M, V4L2_PIX_FMT_YUV444M, V4L2_PIX_FMT_YVU444M, V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SGBRG8, V4L2_PIX_FMT_SGRBG8, V4L2_PIX_FMT_SRGGB8, V4L2_PIX_FMT_SBGGR10, V4L2_PIX_FMT_SGBRG10, V4L2_PIX_FMT_SGRBG10, V4L2_PIX_FMT_SRGGB10, V4L2_PIX_FMT_SBGGR10P, V4L2_PIX_FMT_SGBRG10P, V4L2_PIX_FMT_SGRBG10P, V4L2_PIX_FMT_SRGGB10P, V4L2_PIX_FMT_SBGGR10ALAW8, V4L2_PIX_FMT_SGBRG10ALAW8, V4L2_PIX_FMT_SGRBG10ALAW8, V4L2_PIX_FMT_SRGGB10ALAW8, V4L2_PIX_FMT_SBGGR10DPCM8, V4L2_PIX_FMT_SGBRG10DPCM8, V4L2_PIX_FMT_SGRBG10DPCM8, V4L2_PIX_FMT_SRGGB10DPCM8, V4L2_PIX_FMT_SBGGR12, V4L2_PIX_FMT_SGBRG12, V4L2_PIX_FMT_SGRBG12, V4L2_PIX_FMT_SRGGB12, V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_DV, V4L2_PIX_FMT_MPEG, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_H264_NO_SC, V4L2_PIX_FMT_H264_MVC, V4L2_PIX_FMT_H263, V4L2_PIX_FMT_MPEG1, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_XVID, V4L2_PIX_FMT_VC1_ANNEX_G, V4L2_PIX_FMT_VC1_ANNEX_L, V4L2_PIX_FMT_VP8, V4L2_PIX_FMT_VP9, V4L2_PIX_FMT_HEVC, V4L2_PIX_FMT_CPIA1, V4L2_PIX_FMT_WNVA, V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_SN9C20X_I420, V4L2_PIX_FMT_PWC1, V4L2_PIX_FMT_PWC2, V4L2_PIX_FMT_ET61X251, V4L2_PIX_FMT_SPCA501, V4L2_PIX_FMT_SPCA505, V4L2_PIX_FMT_SPCA508, V4L2_PIX_FMT_SPCA561, V4L2_PIX_FMT_PAC207, V4L2_PIX_FMT_MR97310A, V4L2_PIX_FMT_JL2005BCD, V4L2_PIX_FMT_SN9C2028, V4L2_PIX_FMT_SQ905C, V4L2_PIX_FMT_PJPG, V4L2_PIX_FMT_OV511, V4L2_PIX_FMT_OV518, V4L2_PIX_FMT_STV0680, V4L2_PIX_FMT_TM6000, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_PIX_FMT_KONICA420, V4L2_PIX_FMT_JPGL, V4L2_PIX_FMT_SE401, V4L2_PIX_FMT_S5C_UYVY_JPG, V4L2_PIX_FMT_Y8I, V4L2_PIX_FMT_Y12I, V4L2_PIX_FMT_Z16
v4l2_meta_data_formats = V4L2_META_FMT_VSP1_HGO, V4L2_META_FMT_VSP1_HGT, V4L2_META_FMT_UVC, V4L2_META_FMT_D4XX, V4L2_META_FMT_UVC_MSXU_1_5, V4L2_META_FMT_VIVID, V4L2_META_FMT_RK_ISP1_PARAMS, V4L2_META_FMT_RK_ISP1_STAT_3A, V4L2_META_FMT_RK_ISP1_EXT_PARAMS, V4L2_META_FMT_C3ISP_PARAMS, V4L2_META_FMT_C3ISP_STATS, V4L2_META_FMT_RPI_BE_CFG, V4L2_META_FMT_RPI_FE_CFG, V4L2_META_FMT_RPI_FE_STATS, V4L2_META_FMT_MALI_C55_PARAMS, V4L2_META_FMT_MALI_C55_STATS, V4L2_META_FMT_GENERIC_8, V4L2_META_FMT_GENERIC_CSI2_10, V4L2_META_FMT_GENERIC_CSI2_12, V4L2_META_FMT_GENERIC_CSI2_14, V4L2_META_FMT_GENERIC_CSI2_16, V4L2_META_FMT_GENERIC_CSI2_20, V4L2_META_FMT_GENERIC_CSI2_24
v4l2_fmtdesc_flags = V4L2_FMT_FLAG_COMPRESSED, V4L2_FMT_FLAG_EMULATED, V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, V4L2_FMT_FLAG_DYN_RESOLUTION, V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL, V4L2_FMT_FLAG_CSC_COLORSPACE, V4L2_FMT_FLAG_CSC_XFER_FUNC, V4L2_FMT_FLAG_CSC_YCBCR_ENC, V4L2_FMT_FLAG_CSC_HSV_ENC, V4L2_FMT_FLAG_CSC_QUANTIZATION, V4L2_FMT_FLAG_META_LINE_BASED
v4l2_capability_capabilities = V4L2_CAP_VIDEO_CAPTURE, V4L2_CAP_VIDEO_OUTPUT, V4L2_CAP_VIDEO_OVERLAY, V4L2_CAP_VBI_CAPTURE, V4L2_CAP_VBI_OUTPUT, V4L2_CAP_SLICED_VBI_CAPTURE, V4L2_CAP_SLICED_VBI_OUTPUT, V4L2_CAP_RDS_CAPTURE, V4L2_CAP_VIDEO_OUTPUT_OVERLAY, V4L2_CAP_HW_FREQ_SEEK, V4L2_CAP_RDS_OUTPUT, V4L2_CAP_VIDEO_CAPTURE_MPLANE, V4L2_CAP_VIDEO_OUTPUT_MPLANE, V4L2_CAP_VIDEO_M2M_MPLANE, V4L2_CAP_VIDEO_M2M, V4L2_CAP_TUNER, V4L2_CAP_AUDIO, V4L2_CAP_RADIO, V4L2_CAP_MODULATOR, V4L2_CAP_SDR_CAPTURE, V4L2_CAP_EXT_PIX_FORMAT, V4L2_CAP_SDR_OUTPUT, V4L2_CAP_META_CAPTURE, V4L2_CAP_READWRITE, V4L2_CAP_EDID, V4L2_CAP_STREAMING, V4L2_CAP_META_OUTPUT, V4L2_CAP_TOUCH, V4L2_CAP_IO_MC, V4L2_CAP_DEVICE_CAPS
v4l2_framebuffer_capability = V4L2_FBUF_CAP_EXTERNOVERLAY, V4L2_FBUF_CAP_CHROMAKEY, V4L2_FBUF_CAP_LOCAL_ALPHA, V4L2_FBUF_CAP_GLOBAL_ALPHA, V4L2_FBUF_CAP_LOCAL_INV_ALPHA, V4L2_FBUF_CAP_SRC_CHROMAKEY
v4l2_framebuffer_flags = V4L2_FBUF_FLAG_PRIMARY, V4L2_FBUF_FLAG_OVERLAY, V4L2_FBUF_FLAG_CHROMAKEY, V4L2_FBUF_FLAG_LOCAL_ALPHA, V4L2_FBUF_FLAG_GLOBAL_ALPHA, V4L2_FBUF_FLAG_LOCAL_INV_ALPHA, V4L2_FBUF_FLAG_SRC_CHROMAKEY
v4l2_vbi_format_flags = V4L2_VBI_UNSYNC, V4L2_VBI_INTERLACED, V4L2_VBI_ITU_525_F1_START, V4L2_VBI_ITU_525_F2_START, V4L2_VBI_ITU_625_F1_START, V4L2_VBI_ITU_625_F2_START
v4l2_buffer_flags = V4L2_BUF_FLAG_MAPPED, V4L2_BUF_FLAG_QUEUED, V4L2_BUF_FLAG_DONE, V4L2_BUF_FLAG_KEYFRAME, V4L2_BUF_FLAG_PFRAME, V4L2_BUF_FLAG_BFRAME, V4L2_BUF_FLAG_ERROR, V4L2_BUF_FLAG_IN_REQUEST, V4L2_BUF_FLAG_TIMECODE, V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF, V4L2_BUF_FLAG_PREPARED, V4L2_BUF_FLAG_NO_CACHE_INVALIDATE, V4L2_BUF_FLAG_NO_CACHE_CLEAN, V4L2_BUF_FLAG_TIMESTAMP_MASK, V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN, V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC, V4L2_BUF_FLAG_TIMESTAMP_COPY, V4L2_BUF_FLAG_TSTAMP_SRC_MASK, V4L2_BUF_FLAG_TSTAMP_SRC_EOF, V4L2_BUF_FLAG_TSTAMP_SRC_SOE, V4L2_BUF_FLAG_LAST, V4L2_BUF_FLAG_REQUEST_FD
v4l2_timecode_type = V4L2_TC_TYPE_24FPS, V4L2_TC_TYPE_25FPS, V4L2_TC_TYPE_30FPS, V4L2_TC_TYPE_50FPS, V4L2_TC_TYPE_60FPS
v4l2_timecode_flags = V4L2_TC_FLAG_DROPFRAME, V4L2_TC_FLAG_COLORFRAME, V4L2_TC_USERBITS_field, V4L2_TC_USERBITS_USERDEFINED, V4L2_TC_USERBITS_8BITCHARS
v4l2_captureparm_cap = V4L2_CAP_TIMEPERFRAME
v4l2_captureparm_mode = V4L2_MODE_HIGHQUALITY
v4l2_tuner_capability = V4L2_TUNER_CAP_LOW, V4L2_TUNER_CAP_NORM, V4L2_TUNER_CAP_HWSEEK_BOUNDED, V4L2_TUNER_CAP_HWSEEK_WRAP, V4L2_TUNER_CAP_STEREO, V4L2_TUNER_CAP_LANG2, V4L2_TUNER_CAP_SAP, V4L2_TUNER_CAP_LANG1, V4L2_TUNER_CAP_RDS, V4L2_TUNER_CAP_RDS_BLOCK_IO, V4L2_TUNER_CAP_RDS_CONTROLS, V4L2_TUNER_CAP_FREQ_BANDS, V4L2_TUNER_CAP_HWSEEK_PROG_LIM, V4L2_TUNER_CAP_1HZ
v4l2_tuner_rxsubchans = V4L2_TUNER_SUB_MONO, V4L2_TUNER_SUB_STEREO, V4L2_TUNER_SUB_LANG2, V4L2_TUNER_SUB_SAP, V4L2_TUNER_SUB_LANG1, V4L2_TUNER_SUB_RDS
v4l2_tuner_audmode = V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO, V4L2_TUNER_MODE_LANG2, V4L2_TUNER_MODE_SAP, V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG1_LANG2
v4l2_audio_capability = V4L2_AUDCAP_STEREO, V4L2_AUDCAP_AVL
v4l2_audio_mode = V4L2_AUDMODE_AVL
v4l2_control_flags = V4L2_CTRL_FLAG_DISABLED, V4L2_CTRL_FLAG_GRABBED, V4L2_CTRL_FLAG_READ_ONLY, V4L2_CTRL_FLAG_UPDATE, V4L2_CTRL_FLAG_INACTIVE, V4L2_CTRL_FLAG_SLIDER, V4L2_CTRL_FLAG_WRITE_ONLY, V4L2_CTRL_FLAG_VOLATILE, V4L2_CTRL_FLAG_HAS_PAYLOAD, V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, V4L2_CTRL_FLAG_MODIFY_LAYOUT, V4L2_CTRL_FLAG_DYNAMIC_ARRAY, V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX, V4L2_CTRL_FLAG_NEXT_CTRL, V4L2_CTRL_FLAG_NEXT_COMPOUND
v4l2_ext_ctrl_class = V4L2_CTRL_CLASS_USER, V4L2_CTRL_CLASS_CODEC, V4L2_CTRL_CLASS_CAMERA, V4L2_CTRL_CLASS_FM_TX, V4L2_CTRL_CLASS_FLASH, V4L2_CTRL_CLASS_JPEG, V4L2_CTRL_CLASS_IMAGE_SOURCE, V4L2_CTRL_CLASS_IMAGE_PROC, V4L2_CTRL_CLASS_DV, V4L2_CTRL_CLASS_FM_RX, V4L2_CTRL_CLASS_RF_TUNER, V4L2_CTRL_CLASS_DETECT, V4L2_CTRL_ID_MASK, V4L2_CTRL_MAX_DIMS, V4L2_CTRL_WHICH_CUR_VAL, V4L2_CTRL_WHICH_DEF_VAL
#Comeback and add others from include/uapi/linux/videodev2.h#1617. Once after syz-extract able to detect with special chars
v4l2_ext_controls = V4L2_CID_USER_CLASS, V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST, V4L2_CID_SATURATION, V4L2_CID_HUE, V4L2_CID_AUDIO_VOLUME, V4L2_CID_AUDIO_BALANCE, V4L2_CID_AUDIO_BASS, V4L2_CID_AUDIO_TREBLE, V4L2_CID_AUDIO_MUTE, V4L2_CID_AUDIO_LOUDNESS, V4L2_CID_BLACK_LEVEL, V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CID_DO_WHITE_BALANCE, V4L2_CID_RED_BALANCE, V4L2_CID_BLUE_BALANCE, V4L2_CID_GAMMA, V4L2_CID_EXPOSURE, V4L2_CID_AUTOGAIN, V4L2_CID_GAIN, V4L2_CID_HFLIP, V4L2_CID_VFLIP, V4L2_CID_POWER_LINE_FREQUENCY, V4L2_CID_HUE_AUTO, V4L2_CID_WHITE_BALANCE_TEMPERATURE, V4L2_CID_SHARPNESS, V4L2_CID_BACKLIGHT_COMPENSATION, V4L2_CID_CHROMA_AGC, V4L2_CID_COLOR_KILLER, V4L2_CID_COLORFX, V4L2_CID_AUTOBRIGHTNESS, V4L2_CID_BAND_STOP_FILTER, V4L2_CID_ROTATE, V4L2_CID_BG_COLOR, V4L2_CID_CHROMA_GAIN, V4L2_CID_ILLUMINATORS_1, V4L2_CID_ILLUMINATORS_2, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, V4L2_CID_ALPHA_COMPONENT, V4L2_CID_COLORFX_CBCR, V4L2_CID_CODEC_CLASS, V4L2_CID_MPEG_STREAM_TYPE, V4L2_CID_MPEG_STREAM_PID_PMT, V4L2_CID_MPEG_STREAM_PID_AUDIO, V4L2_CID_MPEG_STREAM_PID_VIDEO, V4L2_CID_MPEG_STREAM_PID_PCR, V4L2_CID_MPEG_STREAM_PES_ID_AUDIO, V4L2_CID_MPEG_STREAM_PES_ID_VIDEO, V4L2_CID_MPEG_STREAM_VBI_FMT, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, V4L2_CID_MPEG_AUDIO_ENCODING, V4L2_CID_MPEG_AUDIO_L1_BITRATE, V4L2_CID_MPEG_AUDIO_L2_BITRATE, V4L2_CID_MPEG_AUDIO_L3_BITRATE, V4L2_CID_MPEG_AUDIO_MODE, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, V4L2_CID_MPEG_AUDIO_EMPHASIS, V4L2_CID_MPEG_AUDIO_CRC, V4L2_CID_MPEG_AUDIO_MUTE, V4L2_CID_MPEG_AUDIO_AAC_BITRATE, V4L2_CID_MPEG_AUDIO_AC3_BITRATE, V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK, V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK, V4L2_CID_MPEG_VIDEO_ENCODING, V4L2_CID_MPEG_VIDEO_ASPECT, V4L2_CID_MPEG_VIDEO_B_FRAMES, V4L2_CID_MPEG_VIDEO_GOP_SIZE, V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, V4L2_CID_MPEG_VIDEO_PULLDOWN, V4L2_CID_MPEG_VIDEO_BITRATE_MODE, V4L2_CID_MPEG_VIDEO_BITRATE, V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, V4L2_CID_MPEG_VIDEO_MUTE, V4L2_CID_MPEG_VIDEO_MUTE_YUV, V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, V4L2_CID_MPEG_VIDEO_HEADER_MODE, V4L2_CID_MPEG_VIDEO_MAX_REF_PIC, V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP, V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP, V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP, V4L2_CID_MPEG_VIDEO_H263_MIN_QP, V4L2_CID_MPEG_VIDEO_H263_MAX_QP, V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, V4L2_CID_MPEG_VIDEO_H264_MAX_QP, V4L2_CID_MPEG_VIDEO_H264_MIN_QP, V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT, V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH, V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC, V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING, V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0, V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE, V4L2_CID_MPEG_VIDEO_H264_FMO, V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE, V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP, V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION, V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE, V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH, V4L2_CID_MPEG_VIDEO_H264_ASO, V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER, V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP, V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP, V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP, V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, V4L2_CID_MPEG_VIDEO_MPEG4_QPEL, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, V4L2_CID_MPEG_VIDEO_VBV_SIZE, V4L2_CID_MPEG_VIDEO_DEC_PTS, V4L2_CID_MPEG_VIDEO_DEC_FRAME, V4L2_CID_MPEG_VIDEO_VBV_DELAY, V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE, V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE, V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS, V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4, V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES, V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL, V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS, V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD, V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL, V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, V4L2_CID_MPEG_VIDEO_VPX_MAX_QP, V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP, V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP, V4L2_CID_MPEG_VIDEO_VPX_PROFILE, V4L2_CID_CAMERA_CLASS, V4L2_CID_EXPOSURE_AUTO, V4L2_CID_EXPOSURE_ABSOLUTE, V4L2_CID_EXPOSURE_AUTO_PRIORITY, V4L2_CID_PAN_RELATIVE, V4L2_CID_TILT_RELATIVE, V4L2_CID_PAN_RESET, V4L2_CID_TILT_RESET, V4L2_CID_PAN_ABSOLUTE, V4L2_CID_TILT_ABSOLUTE, V4L2_CID_FOCUS_ABSOLUTE, V4L2_CID_FOCUS_RELATIVE, V4L2_CID_FOCUS_AUTO, V4L2_CID_ZOOM_ABSOLUTE, V4L2_CID_ZOOM_RELATIVE, V4L2_CID_ZOOM_CONTINUOUS, V4L2_CID_PRIVACY, V4L2_CID_IRIS_ABSOLUTE, V4L2_CID_IRIS_RELATIVE, V4L2_CID_AUTO_EXPOSURE_BIAS, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, V4L2_CID_WIDE_DYNAMIC_RANGE, V4L2_CID_IMAGE_STABILIZATION, V4L2_CID_ISO_SENSITIVITY, V4L2_CID_ISO_SENSITIVITY_AUTO, V4L2_CID_EXPOSURE_METERING, V4L2_CID_SCENE_MODE, V4L2_CID_3A_LOCK, V4L2_CID_AUTO_FOCUS_START, V4L2_CID_AUTO_FOCUS_STOP, V4L2_CID_AUTO_FOCUS_STATUS, V4L2_CID_AUTO_FOCUS_RANGE, V4L2_CID_PAN_SPEED, V4L2_CID_TILT_SPEED, V4L2_CID_FM_TX_CLASS, V4L2_CID_RDS_TX_DEVIATION, V4L2_CID_RDS_TX_PI, V4L2_CID_RDS_TX_PTY, V4L2_CID_RDS_TX_PS_NAME, V4L2_CID_RDS_TX_RADIO_TEXT, V4L2_CID_RDS_TX_MONO_STEREO, V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, V4L2_CID_RDS_TX_COMPRESSED, V4L2_CID_RDS_TX_DYNAMIC_PTY, V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, V4L2_CID_RDS_TX_MUSIC_SPEECH, V4L2_CID_RDS_TX_ALT_FREQS_ENABLE, V4L2_CID_RDS_TX_ALT_FREQS, V4L2_CID_AUDIO_LIMITER_ENABLED, V4L2_CID_AUDIO_LIMITER_RELEASE_TIME, V4L2_CID_AUDIO_LIMITER_DEVIATION, V4L2_CID_AUDIO_COMPRESSION_ENABLED, V4L2_CID_AUDIO_COMPRESSION_GAIN, V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME, V4L2_CID_PILOT_TONE_ENABLED, V4L2_CID_PILOT_TONE_DEVIATION, V4L2_CID_PILOT_TONE_FREQUENCY, V4L2_CID_TUNE_PREEMPHASIS, V4L2_CID_TUNE_POWER_LEVEL, V4L2_CID_TUNE_ANTENNA_CAPACITOR, V4L2_CID_FLASH_CLASS, V4L2_CID_FLASH_LED_MODE, V4L2_CID_FLASH_STROBE_SOURCE, V4L2_CID_FLASH_STROBE, V4L2_CID_FLASH_STROBE_STOP, V4L2_CID_FLASH_STROBE_STATUS, V4L2_CID_FLASH_TIMEOUT, V4L2_CID_FLASH_INTENSITY, V4L2_CID_FLASH_TORCH_INTENSITY, V4L2_CID_FLASH_INDICATOR_INTENSITY, V4L2_CID_FLASH_FAULT, V4L2_CID_FLASH_CHARGE, V4L2_CID_FLASH_READY, V4L2_CID_JPEG_CLASS, V4L2_CID_JPEG_CHROMA_SUBSAMPLING, V4L2_CID_JPEG_RESTART_INTERVAL, V4L2_CID_JPEG_COMPRESSION_QUALITY, V4L2_CID_JPEG_ACTIVE_MARKER, V4L2_CID_IMAGE_SOURCE_CLASS, V4L2_CID_VBLANK, V4L2_CID_HBLANK, V4L2_CID_ANALOGUE_GAIN, V4L2_CID_TEST_PATTERN_RED, V4L2_CID_TEST_PATTERN_GREENR, V4L2_CID_TEST_PATTERN_BLUE, V4L2_CID_TEST_PATTERN_GREENB, V4L2_CID_IMAGE_PROC_CLASS, V4L2_CID_LINK_FREQ, V4L2_CID_PIXEL_RATE, V4L2_CID_TEST_PATTERN, V4L2_CID_DV_CLASS, V4L2_CID_DV_TX_HOTPLUG, V4L2_CID_DV_TX_RXSENSE, V4L2_CID_DV_TX_EDID_PRESENT, V4L2_CID_DV_TX_MODE, V4L2_CID_DV_TX_RGB_RANGE, V4L2_CID_DV_TX_IT_CONTENT_TYPE, V4L2_CID_DV_RX_POWER_PRESENT, V4L2_CID_DV_RX_RGB_RANGE, V4L2_CID_DV_RX_IT_CONTENT_TYPE, V4L2_CID_FM_RX_CLASS, V4L2_CID_TUNE_DEEMPHASIS, V4L2_CID_RDS_RECEPTION, V4L2_CID_RF_TUNER_CLASS, V4L2_CID_RF_TUNER_RF_GAIN, V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, V4L2_CID_RF_TUNER_LNA_GAIN, V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, V4L2_CID_RF_TUNER_MIXER_GAIN, V4L2_CID_RF_TUNER_IF_GAIN_AUTO, V4L2_CID_RF_TUNER_IF_GAIN, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, V4L2_CID_RF_TUNER_BANDWIDTH, V4L2_CID_RF_TUNER_PLL_LOCK, V4L2_CID_RDS_RX_PTY, V4L2_CID_RDS_RX_PS_NAME, V4L2_CID_RDS_RX_RADIO_TEXT, V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, V4L2_CID_RDS_RX_MUSIC_SPEECH, V4L2_CID_DETECT_CLASS, V4L2_CID_DETECT_MD_MODE, V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, V4L2_CID_DETECT_MD_THRESHOLD_GRID, V4L2_CID_DETECT_MD_REGION_GRID
v4l2_frmsizetypes = V4L2_FRMSIZE_TYPE_DISCRETE, V4L2_FRMSIZE_TYPE_CONTINUOUS, V4L2_FRMSIZE_TYPE_STEPWISE
v4l2_frmivaltypes = V4L2_FRMIVAL_TYPE_DISCRETE, V4L2_FRMIVAL_TYPE_CONTINUOUS, V4L2_FRMIVAL_TYPE_STEPWISE
v4l2_enc_idx_flags = V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_B, V4L2_ENC_IDX_FRAME_MASK
v4l2_dbg_match_type = V4L2_CHIP_MATCH_BRIDGE, V4L2_CHIP_MATCH_SUBDEV, V4L2_CHIP_MATCH_I2C_DRIVER, V4L2_CHIP_MATCH_I2C_ADDR, V4L2_CHIP_MATCH_AC97
v4l2_frequency_band_modulation = V4L2_BAND_MODULATION_VSB, V4L2_BAND_MODULATION_FM, V4L2_BAND_MODULATION_AM
v4l2_dv_timings_type = V4L2_DV_BT_656_1120
v4l2_bt_timings_interlaced = V4L2_DV_PROGRESSIVE, V4L2_DV_INTERLACED
v4l2_bt_timings_polarities = V4L2_DV_VSYNC_POS_POL, V4L2_DV_HSYNC_POS_POL
v4l2_bt_timings_standards = V4L2_DV_BT_STD_CEA861, V4L2_DV_BT_STD_DMT, V4L2_DV_BT_STD_CVT, V4L2_DV_BT_STD_GTF, V4L2_DV_BT_STD_SDI
v4l2_bt_timings_flags = V4L2_DV_FL_REDUCED_BLANKING, V4L2_DV_FL_CAN_REDUCE_FPS, V4L2_DV_FL_REDUCED_FPS, V4L2_DV_FL_HALF_LINE, V4L2_DV_FL_IS_CE_VIDEO, V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE
v4l2_encoder_cmd_cmd = V4L2_ENC_CMD_START, V4L2_ENC_CMD_STOP, V4L2_ENC_CMD_PAUSE, V4L2_ENC_CMD_RESUME
v4l2_encoder_flags = V4L2_ENC_CMD_STOP_AT_GOP_END
v4l2_decoder_cmd_cmd = V4L2_DEC_CMD_START, V4L2_DEC_CMD_STOP, V4L2_DEC_CMD_PAUSE, V4L2_DEC_CMD_RESUME
v4l2_decoder_cmd_flags = V4L2_DEC_CMD_START_MUTE_AUDIO, V4L2_DEC_CMD_PAUSE_TO_BLACK, V4L2_DEC_CMD_STOP_TO_BLACK, V4L2_DEC_CMD_STOP_IMMEDIATELY
v4l2_decoder_cmd_format = V4L2_DEC_START_FMT_NONE, V4L2_DEC_START_FMT_GOP
v4l2_event_src_changes = V4L2_EVENT_SRC_CH_RESOLUTION
v4l2_event_type = V4L2_EVENT_ALL, V4L2_EVENT_VSYNC, V4L2_EVENT_EOS, V4L2_EVENT_CTRL, V4L2_EVENT_FRAME_SYNC, V4L2_EVENT_SOURCE_CHANGE, V4L2_EVENT_MOTION_DET, V4L2_EVENT_PRIVATE_START
v4l2_event_ctrl_changes = V4L2_EVENT_CTRL_CH_VALUE, V4L2_EVENT_CTRL_CH_FLAGS, V4L2_EVENT_CTRL_CH_RANGE
v4l2_event_motion_det_flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ
v4l2_event_subscription_flags = V4L2_EVENT_SUB_FL_SEND_INITIAL, V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK
v4l2_selection_target = V4L2_SEL_TGT_CROP, V4L2_SEL_TGT_CROP_DEFAULT, V4L2_SEL_TGT_CROP_BOUNDS, V4L2_SEL_TGT_NATIVE_SIZE, V4L2_SEL_TGT_COMPOSE, V4L2_SEL_TGT_COMPOSE_DEFAULT, V4L2_SEL_TGT_COMPOSE_BOUNDS, V4L2_SEL_TGT_COMPOSE_PADDED
v4l2_selection_flags = V4L2_SEL_FLAG_GE, V4L2_SEL_FLAG_LE, V4L2_SEL_FLAG_KEEP_CONFIG
v4l2_bt_timings_cap_capabilities = V4L2_DV_BT_CAP_INTERLACED, V4L2_DV_BT_CAP_PROGRESSIVE, V4L2_DV_BT_CAP_REDUCED_BLANKING, V4L2_DV_BT_CAP_CUSTOM
v4l2_dbg_chip_info_flags = V4L2_CHIP_FL_READABLE, V4L2_CHIP_FL_WRITABLE
v4l2_std_id = V4L2_STD_PAL_B, V4L2_STD_PAL_B1, V4L2_STD_PAL_G, V4L2_STD_PAL_H, V4L2_STD_PAL_I, V4L2_STD_PAL_D, V4L2_STD_PAL_D1, V4L2_STD_PAL_K, V4L2_STD_PAL_M, V4L2_STD_PAL_N, V4L2_STD_PAL_Nc, V4L2_STD_PAL_60, V4L2_STD_NTSC_M, V4L2_STD_NTSC_M_JP, V4L2_STD_NTSC_443, V4L2_STD_NTSC_M_KR, V4L2_STD_SECAM_B, V4L2_STD_SECAM_D, V4L2_STD_SECAM_G, V4L2_STD_SECAM_H, V4L2_STD_SECAM_K, V4L2_STD_SECAM_K1, V4L2_STD_SECAM_L, V4L2_STD_SECAM_LC, V4L2_STD_ATSC_8_VSB, V4L2_STD_ATSC_16_VSB, V4L2_STD_NTSC, V4L2_STD_SECAM_DK, V4L2_STD_SECAM, V4L2_STD_PAL_BG, V4L2_STD_PAL_DK, V4L2_STD_PAL, V4L2_STD_B, V4L2_STD_G, V4L2_STD_H, V4L2_STD_L, V4L2_STD_GH, V4L2_STD_DK, V4L2_STD_BG, V4L2_STD_MN, V4L2_STD_MTS, V4L2_STD_525_60, V4L2_STD_625_50, V4L2_STD_ATSC, V4L2_STD_UNKNOWN, V4L2_STD_ALL
v4l2_input_status = V4L2_IN_ST_NO_POWER, V4L2_IN_ST_NO_SIGNAL, V4L2_IN_ST_NO_COLOR, V4L2_IN_ST_HFLIP, V4L2_IN_ST_VFLIP, V4L2_IN_ST_NO_H_LOCK, V4L2_IN_ST_COLOR_KILL, V4L2_IN_ST_NO_V_LOCK, V4L2_IN_ST_NO_STD_LOCK, V4L2_IN_ST_NO_SYNC, V4L2_IN_ST_NO_EQU, V4L2_IN_ST_NO_CARRIER, V4L2_IN_ST_MACROVISION, V4L2_IN_ST_NO_ACCESS, V4L2_IN_ST_VTR
v4l2_input_type = V4L2_INPUT_TYPE_TUNER, V4L2_INPUT_TYPE_CAMERA, V4L2_INPUT_TYPE_TOUCH
v4l2_input_capabilities = V4L2_IN_CAP_DV_TIMINGS, V4L2_IN_CAP_CUSTOM_TIMINGS, V4L2_IN_CAP_STD, V4L2_IN_CAP_NATIVE_SIZE
v4l2_output_type = V4L2_OUTPUT_TYPE_MODULATOR, V4L2_OUTPUT_TYPE_ANALOG, V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY
v4l2_output_capabilities = V4L2_OUT_CAP_DV_TIMINGS, V4L2_OUT_CAP_CUSTOM_TIMINGS, V4L2_OUT_CAP_STD, V4L2_OUT_CAP_NATIVE_SIZE
v4l2_query_ext_ctrl = V4L2_CTRL_FLAG_NEXT_CTRL, V4L2_CTRL_FLAG_NEXT_COMPOUND
# These are actually defined in the newer kernel versions.
# But the newer kernel versions don't build with make extract.
# This can be removed once we can regenerate consts on at least v6.19-rc3.
define V4L2_META_FMT_MALI_C55_PARAMS 1345664323
define V4L2_META_FMT_MALI_C55_STATS 1395995971
]
|
| 185/2 |
2026/07/30 12:38 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 50795
output: 475
thoughts: 280
Thoughts: **Understanding Syzkaller's Device Open Functions**
Okay, so I'm looking at this `syz_open_dev$video` function call and I'm seeing a device string like `/dev/video#` and it's throwing a `bad string value` error, specifically expecting `/dev/video#\x00`. Right, right. That means the string *must* be exactly `"/dev/video#\x00"`, the null-terminated version. And Syzkaller is going to replace the `#` with the `id` argument. Hmm, okay, so looking at the function signature again: `syz_open_dev$video(dev ptr[in, string["/dev/video#"]], id intptr, flags flags[open_flags]) fd_video`. The `id` is an `intptr`. Got it.
So, for this `syz_open_dev$video` call, I need to provide `"/dev/video#\x00"` as the device string and I should pass `0` for the `id`.
Thinking ahead, the same principle applies to other similar functions. I look at `syz_open_dev$I2C`: `syz_open_dev$I2C(dev ptr[in, string["/dev/i2c-#"]], id intptr, flags flags[open_flags]) fd_i2c`. Yep, clearly, I should use `"/dev/i2c-#\x00"` and `0` for the `id` there as well. The pattern is clear now.
|
| 186/2 |
2026/07/30 12:38 |
tool |
reproduce-crash |
2m
Args: map[ReproSyz:r0 = syz_usb_connect$hid(3, 0, &AUTO, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r4 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID:repro/396707d321d3e0ce83a74314715d5b162d86ae82 ReproducedBugTitle: ReproducedCrashReport:]
|
| 187/2 |
2026/07/30 12:40 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 51971
output: 60
thoughts: 11
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Analyzing the Stability and Scope**
No crash. Good. That's the baseline we were aiming for. Now, let's drill down into the coverage. What specifically is meant here? Are we talking about test coverage, error handling coverage, or perhaps even performance envelope coverage? I need to understand the intent to interpret the following statement effectively. Let's see what's being looked at here.
|
| 188/2 |
2026/07/30 12:41 |
tool |
get-coverage-files |
0m
Args: map[ExecutionCachedID:repro/396707d321d3e0ce83a74314715d5b162d86ae82]
Results: map[Files:[arch/x86/entry/vsyscall/vsyscall_64.c arch/x86/include/asm/atomic64_64.h arch/x86/include/asm/bitops.h arch/x86/include/asm/compat.h arch/x86/include/asm/cpufeature.h arch/x86/include/asm/irqflags.h arch/x86/include/asm/jump_label.h arch/x86/include/asm/mmu_context.h arch/x86/include/asm/page.h arch/x86/include/asm/pgtable.h arch/x86/include/asm/pkru.h arch/x86/include/asm/preempt.h arch/x86/include/asm/trace/fpu.h arch/x86/kernel/cpu/aperfmperf.c arch/x86/kernel/fpu/context.h arch/x86/kernel/fpu/core.c arch/x86/kernel/fpu/internal.h arch/x86/kernel/fpu/xstate.c arch/x86/kernel/tsc.c arch/x86/mm/fault.c arch/x86/mm/maccess.c arch/x86/mm/pgtable.c arch/x86/pci/common.c arch/x86/pci/direct.c block/blk-cgroup.c drivers/acpi/acpica/nsaccess.c drivers/acpi/acpica/nsdump.c drivers/acpi/acpica/nssearch.c drivers/acpi/acpica/nsutils.c drivers/acpi/acpica/nsxfname.c drivers/acpi/acpica/utascii.c drivers/acpi/acpica/utdebug.c drivers/acpi/acpica/utmutex.c drivers/acpi/acpica/utstring.c drivers/acpi/device_pm.c drivers/acpi/osl.c drivers/acpi/property.c drivers/acpi/utils.c drivers/base/core.c drivers/base/map.c drivers/base/power/qos.c drivers/base/power/runtime.c drivers/base/power/wakeirq.c drivers/char/misc.c drivers/i2c/busses/i2c-i801.c drivers/i2c/i2c-core-base.c drivers/i2c/i2c-core-smbus.c drivers/i2c/i2c-core.h drivers/i2c/i2c-dev.c drivers/media/common/videobuf2/videobuf2-core.c drivers/media/common/videobuf2/videobuf2-v4l2.c drivers/media/mc/mc-request.c drivers/media/test-drivers/vicodec/codec-v4l2-fwht.c drivers/media/test-drivers/vicodec/vicodec-core.c drivers/media/v4l2-core/v4l2-ctrls-core.c drivers/media/v4l2-core/v4l2-ctrls-defs.c drivers/media/v4l2-core/v4l2-ctrls-request.c drivers/media/v4l2-core/v4l2-dev.c drivers/media/v4l2-core/v4l2-fh.c drivers/media/v4l2-core/v4l2-mem2mem.c drivers/pci/access.c drivers/pci/ats.c drivers/pci/host-bridge.c drivers/pci/iov.c drivers/pci/msi/api.c drivers/pci/msi/msi.c drivers/pci/pci-acpi.c drivers/pci/pci-driver.c drivers/pci/pci.c drivers/pci/pcie/aer.c drivers/pci/pcie/aspm.c drivers/pci/quirks.c drivers/pci/rebar.c drivers/pci/vc.c drivers/usb/gadget/legacy/raw_gadget.c fs/char_dev.c fs/d_path.c fs/dcache.c fs/file.c fs/file_table.c fs/ioctl.c fs/libfs.c fs/mnt_idmapping.c fs/namei.c fs/namespace.c fs/notify/fsnotify.c fs/open.c include/acpi/acpi_bus.h include/asm-generic/bitops/instrumented-non-atomic.h include/linux/atomic/atomic-arch-fallback.h include/linux/atomic/atomic-instrumented.h include/linux/atomic/atomic-long.h include/linux/audit.h include/linux/bit_spinlock.h include/linux/cgroup.h include/linux/clockchips.h include/linux/cpumask.h include/linux/cred.h include/linux/dcache.h include/linux/delayed_call.h include/linux/device.h include/linux/device_cgroup.h include/linux/err.h include/linux/file.h include/linux/file_ref.h include/linux/filelock.h include/linux/find.h include/linux/folio_batch.h include/linux/fortify-string.h include/linux/fs.h include/linux/fs/super.h include/linux/fsnotify.h include/linux/fsnotify_backend.h include/linux/hrtimer.h include/linux/instrumented.h include/linux/jiffies.h include/linux/jump_label.h include/linux/kernel.h include/linux/kref.h include/linux/list.h include/linux/list_bl.h include/linux/llist.h include/linux/log2.h include/linux/lsm_hook_defs.h include/linux/maple_tree.h include/linux/memcontrol.h include/linux/mempolicy.h include/linux/mm.h include/linux/mmzone.h include/linux/mount.h include/linux/nodemask.h include/linux/page-flags.h include/linux/page_ext.h include/linux/page_ref.h include/linux/pagemap.h include/linux/perf_event.h include/linux/pgtable.h include/linux/pid.h include/linux/pm_qos.h include/linux/preempt.h include/linux/rbtree.h include/linux/rbtree_latch.h include/linux/rculist_bl.h include/linux/rcupdate.h include/linux/refcount.h include/linux/rmap.h include/linux/rtmutex.h include/linux/sched.h include/linux/sched/isolation.h include/linux/seqlock.h include/linux/spinlock_rt.h include/linux/srcu.h include/linux/swap.h include/linux/thread_info.h include/linux/uaccess.h include/linux/ucopysize.h include/linux/userfaultfd_k.h include/linux/workqueue.h include/linux/xarray.h include/trace/events/exceptions.h include/trace/events/filemap.h include/trace/events/kmem.h include/trace/events/rpm.h include/trace/events/smbus.h include/trace/events/timer.h kernel/bpf/core.c kernel/cgroup/rstat.c kernel/kthread.c kernel/pid.c kernel/printk/printk_safe.c kernel/time/clockevents.c kernel/time/hrtimer.c kernel/time/posix-timers.c kernel/time/tick-oneshot.c kernel/time/tick-sched.c kernel/time/time.c kernel/time/timekeeping.c lib/cpumask.c lib/errseq.c lib/idr.c lib/iomap.c lib/kobject.c lib/lockref.c lib/maple_tree.c lib/percpu_counter.c lib/plist.c lib/radix-tree.c lib/strncpy_from_user.c lib/timerqueue.c lib/usercopy.c lib/vsprintf.c lib/xarray.c mm/backing-dev.c mm/fail_page_alloc.c mm/filemap.c mm/internal.h mm/list_lru.c mm/maccess.c mm/memory.c mm/mempolicy.c mm/mmap_lock.c mm/page_counter.c mm/page_ext.c mm/page_owner.c mm/page_table_check.c mm/pgtable-generic.c mm/readahead.c mm/rmap.c mm/swap.c mm/swapfile.c security/device_cgroup.c security/integrity/ima/ima_main.c security/landlock/cred.h security/landlock/fs.c security/landlock/ruleset.c security/security.c security/smack/smack_access.c security/smack/smack_lsm.c security/tomoyo/audit.c security/tomoyo/common.c security/tomoyo/common.h security/tomoyo/domain.c security/tomoyo/file.c security/tomoyo/realpath.c security/tomoyo/tomoyo.c security/tomoyo/util.c usercopy_64.c]]
|
| 189/2 |
2026/07/30 12:41 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 55049
output: 19
thoughts: 245
Thoughts: **USB Device Matching and Syzkaller Configuration**
Okay, so I've been digging through the syzkaller coverage, and I see that the `raw_gadget.c` driver is covered. Good, good. But I'm missing something... the coverage doesn't seem to include the `si4713`, `au0828`, or `go7007` drivers! That's a red flag.
Right, I remember now. I was using `syz_usb_connect$hid(3, 0, &AUTO, 0)` to connect a HID device. That explains the lack of coverage for those other drivers. That function is specifically tailored for HID devices, and I need to connect something that corresponds to one of those other device types. Those are radio and video drivers, not HID.
So, how does syzkaller handle USB device matching? It must be by vendor and product IDs, I'd guess. Ah, that's it! When I use `syz_usb_connect$hid`, syzkaller automatically tweaks the vendor/product IDs to align with some known HID driver. Makes perfect sense.
I need to use the more generic `syz_usb_connect` function and provide the correct vendor and product IDs for my target device. Let me check the documentation.
Okay, let's see... `syz_usb_connect` takes `speed`, `dev_len`, `dev`, `cb_len`, and `cb` as arguments. Now to find the right vendor and product IDs... I'll check `vusb.txt`.
|
| 190/2 |
2026/07/30 12:41 |
tool |
read-description |
0m
Args:
Results: map[Output:# Copyright 2019 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
include <linux/types.h>
include <linux/byteorder/generic.h>
include <uapi/linux/usb/ch9.h>
include <uapi/linux/usb/ch11.h>
include <uapi/linux/usb/midi.h>
include <uapi/linux/usb/audio.h>
include <linux/usb/audio-v2.h>
include <linux/usb/audio-v3.h>
include <uapi/linux/hid.h>
include <linux/hid.h>
include <uapi/linux/usb/cdc.h>
include <uapi/linux/if_ether.h>
include <linux/interrupt.h>
include <linux/usb/cdc_ncm.h>
include <drivers/net/usb/asix.h>
# This is a special fd for USB fuzzing and should only be used with syz_usb_* pseudo-syscalls.
# We don't inherit it from the fd resource, to discourage syzkaller calling raw ioctls on it.
resource fd_usb[int32]: -1
# These are generic pseudo-syscalls for emulating arbitrary USB devices.
# They are mostly targeted to cover the enumeration process.
syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io(fd fd_usb, descs ptr[in, vusb_descriptors], resps ptr[in, vusb_responses]) (timeout[300], remote_cover)
syz_usb_ep_write(fd fd_usb, ep int8, len len[data], data ptr[in, array[int8, 0:256]]) (timeout[300], remote_cover)
syz_usb_ep_read(fd fd_usb, ep int8, len len[data], data buffer[out]) (timeout[300], remote_cover)
syz_usb_disconnect(fd fd_usb) (timeout[300], remote_cover)
usb_device_speed = USB_SPEED_UNKNOWN, USB_SPEED_LOW, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_WIRELESS, USB_SPEED_SUPER, USB_SPEED_SUPER_PLUS
# TODO: consider patching idVendor and idProduct for all class specific descriptions in Go code to cover more drivers.
# TODO: custom syz_usb_ep_write() descriptions for all class specific descriptions.
# TODO: consider adding custom vusb_connect_descriptors definitions to all class specific descriptions.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
type usb_device_descriptor_verbose_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] {
bLength const[USB_DT_DEVICE_SIZE, int8]
bDescriptorType const[USB_DT_DEVICE, int8]
bcdUSB USB
bDeviceClass const[CLASS, int8]
bDeviceSubClass const[SUBCLASS, int8]
bDeviceProtocol const[PROTOCOL, int8]
bMaxPacketSize0 PACKET
idVendor const[VENDOR, int16]
idProduct const[PRODUCT, int16]
bcdDevice const[DEVICE, int16]
iManufacturer const[1, int8]
iProduct const[2, int8]
iSerialNumber const[3, int8]
bNumConfigurations len[configs, int8]
configs CFS
} [packed]
type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[flags[usb_versions, int16], CLASS, SUBCLASS, PROTOCOL, flags[usb_device_max_packet_sizes, int8], VENDOR, PRODUCT, DEVICE, CFS]
type usb_device_descriptor_fixed_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[const[USB, int16], CLASS, SUBCLASS, PROTOCOL, const[PACKET, int8], VENDOR, PRODUCT, DEVICE, CFS]
usb_versions = 0x110, 0x200, 0x201, 0x250, 0x300, 0x310
# https://elixir.bootlin.com/linux/v5.1.7/source/drivers/usb/core/hub.c#L4661
usb_device_max_packet_sizes = 8, 16, 32, 64, 255
type usb_config_descriptor_verbose_t[NUM, IFSNUM, ICONFIG, ATTRS, POWER, EXTRA, IFS] {
bLength const[USB_DT_CONFIG_SIZE, int8]
bDescriptorType const[USB_DT_CONFIG, int8]
wTotalLength len[parent, int16]
bNumInterfaces IFSNUM
bConfigurationValue NUM
iConfiguration ICONFIG
bmAttributes ATTRS
bMaxPower POWER
extra EXTRA
interfaces IFS
} [packed]
type usb_config_descriptor_t[NUM, IFSNUM, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, void, IFS]
type usb_config_descriptor_ifaces_array_t[NUM, IFS] usb_config_descriptor_t[NUM, len[interfaces, int8], IFS]
type usb_config_descriptor_fixed_t[NUM, IFSNUM, ATTRS, POWER, IFS] usb_config_descriptor_verbose_t[const[NUM, int8], const[IFSNUM, int8], const[0, int8], const[ATTRS, int8], const[POWER, int8], void, IFS]
type usb_config_descriptor_extra_t[NUM, IFSNUM, EXTRA, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, EXTRA, IFS]
type usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, IIF, EXTRA, EPS] {
bLength const[USB_DT_INTERFACE_SIZE, int8]
bDescriptorType const[USB_DT_INTERFACE, int8]
bInterfaceNumber IFNUM
bAlternateSetting ALTNUM
bNumEndpoints EPSNUM
bInterfaceClass CLASS
bInterfaceSubClass SUBCLASS
bInterfaceProtocol PROTOCOL
iInterface IIF
extra EXTRA
endpoints EPS
} [packed]
type usb_interface_descriptor_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, int8, EXTRA, EPS]
type usb_interface_descriptor_eps_array_t[IFNUM, ALTNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_t[IFNUM, ALTNUM, len[endpoints, int8], CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS]
type usb_interface_descriptor_fixed_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[const[IFNUM, int8], const[ALTNUM, int8], const[EPSNUM, int8], const[CLASS, int8], const[SUBCLASS, int8], const[PROTOCOL, int8], const[0, int8], EXTRA, EPS]
# TODO: non-audio endpoints have USB_DT_ENDPOINT_SIZE.
type usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, PACKET, INTERVAL, REFRESH, SYNCH, EXTRA] {
bLength const[USB_DT_ENDPOINT_AUDIO_SIZE, int8]
bDescriptorType const[USB_DT_ENDPOINT, int8]
bEndpointAddress ADDR
bmAttributes ATTRS
wMaxPacketSize PACKET
bInterval INTERVAL
bRefresh REFRESH
bSynchAddress SYNCH
extra EXTRA
} [packed]
type usb_endpoint_descriptor_t[ADDR, ATTRS, EXTRA] usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, EXTRA]
type usb_endpoint_descriptor_fixed_t[ADDR, ATTRS, PACKET, INTERVAL, EXTRA] usb_endpoint_descriptor_verbose_t[const[ADDR, int8], const[ATTRS, int8], const[PACKET, int16], const[INTERVAL, int8], const[0, int8], const[0, int8], EXTRA]
# TODO: dummy driver has complex requirements for packet sizes, account for those:
# https://elixir.bootlin.com/linux/v5.3.6/source/drivers/usb/gadget/udc/dummy_hcd.c#L497
usb_endpoint_max_packet_sizes = 8, 16, 32, 64, 512, 1023, 1024
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Generic USB device, configuration, interface and endpoint descriptors.
# We only support one configuration per device.
# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct
# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]]
} [packed]
usb_config_descriptor {
inner usb_config_descriptor_ifaces_array_t[int8, array[usb_interface_descriptor, 1:4]]
} [packed]
usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY
# bInterfaceNumber, bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol
# are patched by Go code, see sys/linux/init_vusb.go.
usb_interface_descriptor {
inner usb_interface_descriptor_eps_array_t[int8, int8, const[0, int8], const[0, int8], const[0, int8], array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
} [packed]
usb_endpoint_descriptor {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], array[usb_endpoint_extra_descriptor, 0:2]]
} [packed]
usb_endpoint_addresses = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, USB_DIR_OUT, USB_DIR_IN
usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK
vusb_connect_descriptors {
qual_len len[qual, int32]
qual ptr[in, usb_qualifier_descriptor]
bos_len len[bos, int32]
bos ptr[in, usb_bos_descriptor]
strs_len len[strs, int32]
strs array[vusb_connect_string_descriptor]
} [packed]
vusb_connect_string_descriptor {
len len[str, int32]
str ptr[in, usb_string_descriptor]
} [packed]
vusb_descriptors {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]]
hub_hs ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_HUB, usb_hub_descriptor_hs]]
hub_ss ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_SS_HUB, usb_hub_descriptor_ss]]
} [packed]
vusb_descriptor_generic {
req_type flags[usb_request_types, int8]
desc_type flags[usb_descriptor_types, int8]
len bytesize[data, int32]
data usb_generic_descriptor
} [packed]
usb_request_types = USB_TYPE_STANDARD, USB_TYPE_CLASS, USB_TYPE_VENDOR
type vusb_descriptor_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# TODO: consider doing lookups based on USB_RECIP values.
vusb_responses {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
get_interface ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
get_configuration ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
# TODO: move these into custom descriptions for hub class when they are added.
hub_USB_REQ_GET_STATUS_hub ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_hub_status]]
hub_USB_REQ_GET_STATUS_port ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_port_status]]
# TODO: move these into custom descriptions for asix driver when they are added.
asix_AX_CMD_READ_MII_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MII_REG, int16]]
asix_AX_CMD_STATMNGSTS_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_STATMNGSTS_REG, int8]]
asix_AX_CMD_READ_EEPROM ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_EEPROM, array[int8, 2]]]
asix_AX_CMD_READ_RX_CTL ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_RX_CTL, int16]]
asix_AX_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_NODE_ID, mac_addr]]
asix_AX88172_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX88172_CMD_READ_NODE_ID, mac_addr]]
asix_AX_CMD_READ_PHY_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_PHY_ID, array[int8, 2]]]
asix_AX_CMD_READ_MEDIUM_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MEDIUM_STATUS, int16]]
asix_AX_CMD_READ_MONITOR_MODE ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MONITOR_MODE, int8]]
asix_AX_CMD_READ_GPIOS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_GPIOS, int8]]
asix_AX_CMD_SW_PHY_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_SW_PHY_STATUS, int8]]
} [packed]
vusb_response_generic {
type flags[usb_request_types, int8]
req flags[usb_requests, int8]
len bytesize[data, int32]
data array[int8, 0:256]
} [packed]
usb_requests = USB_REQ_GET_STATUS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, USB_REQ_SET_ADDRESS, USB_REQ_GET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR, USB_REQ_GET_CONFIGURATION, USB_REQ_SET_CONFIGURATION, USB_REQ_GET_INTERFACE, USB_REQ_SET_INTERFACE, USB_REQ_SYNCH_FRAME, USB_REQ_SET_SEL, USB_REQ_SET_ISOCH_DELAY, USB_REQ_SET_ENCRYPTION, USB_REQ_GET_ENCRYPTION, USB_REQ_RPIPE_ABORT, USB_REQ_SET_HANDSHAKE, USB_REQ_RPIPE_RESET, USB_REQ_GET_HANDSHAKE, USB_REQ_SET_CONNECTION, USB_REQ_SET_SECURITY_DATA, USB_REQ_GET_SECURITY_DATA, USB_REQ_SET_WUSB_DATA, USB_REQ_LOOPBACK_DATA_WRITE, USB_REQ_LOOPBACK_DATA_READ, USB_REQ_SET_INTERFACE_DS, USB_REQ_GET_PARTNER_PDO, USB_REQ_GET_BATTERY_STATUS, USB_REQ_SET_PDO, USB_REQ_GET_VDM, USB_REQ_SEND_VDM
type vusb_response_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested by the kernel before the SET_CONFIGURATION request.
# TODO: figure out when is the USB_DT_OTG descriptor used.
# TODO: figure out when is the USB_DT_INTERFACE_ASSOCIATION descriptor used.
# TODO: figure out when is the USB_DT_BOS descriptor used.
type usb_string_descriptor_t[DATA] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_STRING, int8]
data DATA
} [packed]
usb_string_descriptor [
lang_id usb_string_descriptor_t[flags[usb_lang_ids, int16]]
string usb_string_descriptor_t[array[int8, 0:256]]
] [varlen]
usb_lang_ids = 0x436, 0x41c, 0x401, 0x801, 0xc01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001, 0x42b, 0x44d, 0x42c, 0x82c, 0x42d, 0x423, 0x445, 0x402, 0x455, 0x403, 0x404, 0x804, 0xc04, 0x1004, 0x1404, 0x41a, 0x405, 0x406, 0x413, 0x813, 0x409, 0x809, 0xc09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x425, 0x438, 0x429, 0x40b, 0x40c, 0x80c, 0xc0c, 0x100c, 0x140c, 0x180c, 0x437, 0x407, 0x807, 0xc07, 0x1007, 0x1407, 0x408, 0x447, 0x40d, 0x439, 0x40e, 0x40f, 0x421, 0x410, 0x810, 0x411, 0x44b, 0x860, 0x43f, 0x457, 0x412, 0x812, 0x426, 0x427, 0x827, 0x42f, 0x43e, 0x83e, 0x44c, 0x458, 0x44e, 0x861, 0x414, 0x814, 0x448, 0x415, 0x416, 0x816, 0x446, 0x418, 0x419, 0x44f, 0xc1a, 0x81a, 0x459, 0x41b, 0x424, 0x40a, 0x80a, 0xc0a, 0x100a, 0x140a, 0x180a, 0x1c0a, 0x200a, 0x240a, 0x280a, 0x2c0a, 0x300a, 0x340a, 0x380a, 0x3c0a, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a, 0x430, 0x441, 0x41d, 0x81d, 0x449, 0x444, 0x44a, 0x41e, 0x41f, 0x422, 0x420, 0x820, 0x443, 0x843, 0x42a, 0x4ff, 0xf0ff, 0xf4ff, 0xf8ff, 0xfcff
usb_qualifier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_QUALIFIER, int8]
bcdUSB flags[usb_versions, int16]
bDeviceClass int8
bDeviceSubClass int8
bDeviceProtocol int8
bMaxPacketSize0 flags[usb_device_max_packet_sizes, int8]
bNumConfigurations int8
bRESERVED const[0, int8]
} [packed]
usb_bos_descriptor {
bLength const[USB_DT_BOS_SIZE, int8]
bDescriptorType const[USB_DT_BOS, int8]
wTotalLength len[parent, int16]
bNumDeviceCaps len[caps, int8]
caps array[usb_dev_cap, 0:6]
} [packed]
usb_dev_cap [
generic usb_generic_cap_descriptor
wireless usb_wireless_cap_descriptor
ext_cap usb_ext_cap_descriptor
ss_cap usb_ss_cap_descriptor
ss_container_id usb_ss_container_id_descriptor
ssp_cap usb_ssp_cap_descriptor
ptm_cap usb_ptm_cap_descriptor
] [varlen]
usb_generic_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType flags[usb_capability_types, int8]
data array[int8, 0:256]
} [packed]
usb_capability_types = USB_CAP_TYPE_WIRELESS_USB, USB_CAP_TYPE_EXT, USB_SS_CAP_TYPE, USB_SSP_CAP_TYPE, CONTAINER_ID_TYPE, USB_PTM_CAP_TYPE
usb_wireless_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_WIRELESS_USB, int8]
bmAttributes flags[usb_wireless_cap_attributes, int8]
wPHYRates flags[usb_wireless_cap_phyrates, int16]
bmTFITXPowerInfo int8
bmFFITXPowerInfo int8
bmBandGroup int16
bReserved int8
} [packed]
usb_wireless_cap_attributes = USB_WIRELESS_P2P_DRD, USB_WIRELESS_BEACON_MASK, USB_WIRELESS_BEACON_SELF, USB_WIRELESS_BEACON_DIRECTED, USB_WIRELESS_BEACON_NONE
usb_wireless_cap_phyrates = USB_WIRELESS_PHY_53, USB_WIRELESS_PHY_80, USB_WIRELESS_PHY_107, USB_WIRELESS_PHY_160, USB_WIRELESS_PHY_200, USB_WIRELESS_PHY_320, USB_WIRELESS_PHY_400, USB_WIRELESS_PHY_480
usb_ext_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_EXT, int8]
bmAttributes1 flags[usb_ext_cap_attributes, int32:8]
bmAttributes2 int32:4
bmAttributes3 int32:4
bmAttributes4 int32:16
} [packed]
usb_ext_cap_attributes = USB_LPM_SUPPORT, USB_BESL_SUPPORT, USB_BESL_BASELINE_VALID, USB_BESL_DEEP_VALID
usb_ss_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SS_CAP_TYPE, int8]
bmAttributes flags[usb_ss_cap_attributes, int8]
wSpeedSupported flags[usb_ss_cap_speed, int16]
bFunctionalitySupport int8
bU1devExitLat int8
bU2DevExitLat int16
} [packed]
usb_ss_cap_attributes = USB_LTM_SUPPORT
usb_ss_cap_speed = USB_LOW_SPEED_OPERATION, USB_FULL_SPEED_OPERATION, USB_HIGH_SPEED_OPERATION, USB_5GBPS_OPERATION
usb_ss_container_id_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[CONTAINER_ID_TYPE, int8]
bReserved int8
ContainerID array[int8, 16]
} [packed]
usb_ssp_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SSP_CAP_TYPE, int8]
bReserved int8
bmAttributesSublinkSpeeds len[bmSublinkSpeedAttr, int32:5]
bmAttributesSpeedIDs int32:27
wFunctionalitySupport flags[usb_ssp_cap_funcs, int16]
wReserved int16
bmSublinkSpeedAttr array[flags[usb_ssp_cap_sublink_speeds, int32], 0:6]
} [packed]
usb_ssp_cap_funcs = USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, USB_SSP_MIN_RX_LANE_COUNT, USB_SSP_MIN_TX_LANE_COUNT
usb_ssp_cap_sublink_speeds = USB_SSP_SUBLINK_SPEED_SSID, USB_SSP_SUBLINK_SPEED_LSE, USB_SSP_SUBLINK_SPEED_ST, USB_SSP_SUBLINK_SPEED_RSVD, USB_SSP_SUBLINK_SPEED_LP, USB_SSP_SUBLINK_SPEED_LSM
usb_ptm_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_PTM_CAP_TYPE, int8]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Extra USB descriptors that come after an interface or an endpoint descriptor.
# TODO: consider removing class specific descriptors here for described classes.
usb_interface_extra_descriptor [
generic usb_generic_descriptor
hid_hid usb_hid_descriptor_hid
cdc_ecm usb_cdc_header_ecm
cdc_ncm usb_cdc_header_ncm
uac_control uac_control_iface_extra_descriptors
uac_as uac_as_iface_extra_descriptors
] [varlen]
usb_endpoint_extra_descriptor [
generic usb_generic_descriptor
uac_iso uac_iso_endpoint_descriptor
] [varlen]
usb_generic_descriptor {
bLength len[parent, int8]
bDescriptorType flags[usb_descriptor_types, int8]
data array[int8, 0:256]
} [packed]
usb_descriptor_types = USB_DT_DEVICE, USB_DT_CONFIG, USB_DT_STRING, USB_DT_INTERFACE, USB_DT_ENDPOINT, USB_DT_DEVICE_QUALIFIER, USB_DT_OTHER_SPEED_CONFIG, USB_DT_INTERFACE_POWER, USB_DT_OTG, USB_DT_DEBUG, USB_DT_INTERFACE_ASSOCIATION, USB_DT_SECURITY, USB_DT_KEY, USB_DT_ENCRYPTION_TYPE, USB_DT_BOS, USB_DT_DEVICE_CAPABILITY, USB_DT_WIRELESS_ENDPOINT_COMP, USB_DT_WIRE_ADAPTER, USB_DT_RPIPE, USB_DT_CS_RADIO_CONTROL, USB_DT_PIPE_USAGE, USB_DT_SS_ENDPOINT_COMP, USB_DT_SSP_ISOC_ENDPOINT_COMP, HID_DT_HID, HID_DT_REPORT, HID_DT_PHYSICAL
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested after the SET_CONFIGURATION request.
usb_hub_descriptor_hs {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
DeviceRemovable array[int8, USB_HUB_PORTS_BITS]
PortPwrCtrlMask array[int8, USB_HUB_PORTS_BITS]
} [packed]
usb_hub_descriptor_ss {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_SS_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
bHubHdrDecLat int8
wHubDelay int16
DeviceRemovable int16
} [packed]
define USB_HUB_PORTS_BITS ((USB_MAXCHILDREN + 1 + 7) / 8)
usb_hub_characteristics = HUB_CHAR_LPSM, HUB_CHAR_COMMON_LPSM, HUB_CHAR_INDV_PORT_LPSM, HUB_CHAR_NO_LPSM, HUB_CHAR_COMPOUND, HUB_CHAR_OCPM, HUB_CHAR_COMMON_OCPM, HUB_CHAR_INDV_PORT_OCPM, HUB_CHAR_NO_OCPM, HUB_CHAR_TTTT, HUB_CHAR_PORTIND
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Replies to USB control requests requested after the SET_CONFIGURATION request.
usb_port_status {
wPortStatus flags[usb_port_status_flags, int16]
wPortChange flags[usb_port_change_flags, int16]
dwExtPortStatus array[flags[usb_ext_port_status_flags, int32], 0:1]
} [packed]
usb_port_status_flags = USB_PORT_STAT_CONNECTION, USB_PORT_STAT_ENABLE, USB_PORT_STAT_SUSPEND, USB_PORT_STAT_OVERCURRENT, USB_PORT_STAT_RESET, USB_PORT_STAT_L1, USB_PORT_STAT_POWER, USB_PORT_STAT_LOW_SPEED, USB_PORT_STAT_HIGH_SPEED, USB_PORT_STAT_TEST, USB_PORT_STAT_INDICATOR, USB_PORT_STAT_LINK_STATE, USB_SS_PORT_STAT_POWER, USB_SS_PORT_STAT_SPEED, USB_PORT_STAT_SPEED_5GBPS, USB_SS_PORT_LS_U0, USB_SS_PORT_LS_U1, USB_SS_PORT_LS_U2, USB_SS_PORT_LS_U3, USB_SS_PORT_LS_SS_DISABLED, USB_SS_PORT_LS_RX_DETECT, USB_SS_PORT_LS_SS_INACTIVE, USB_SS_PORT_LS_POLLING, USB_SS_PORT_LS_RECOVERY, USB_SS_PORT_LS_HOT_RESET, USB_SS_PORT_LS_COMP_MOD, USB_SS_PORT_LS_LOOPBACK
usb_port_change_flags = USB_PORT_STAT_C_CONNECTION, USB_PORT_STAT_C_ENABLE, USB_PORT_STAT_C_SUSPEND, USB_PORT_STAT_C_OVERCURRENT, USB_PORT_STAT_C_RESET, USB_PORT_STAT_C_L1, USB_PORT_STAT_C_BH_RESET, USB_PORT_STAT_C_LINK_STATE, USB_PORT_STAT_C_CONFIG_ERROR
usb_ext_port_status_flags = USB_EXT_PORT_STAT_RX_SPEED_ID, USB_EXT_PORT_STAT_TX_SPEED_ID, USB_EXT_PORT_STAT_RX_LANES, USB_EXT_PORT_STAT_TX_LANES
usb_hub_status {
wHubStatus flags[usb_hub_status_flags, int16]
wHubChange flags[usb_hub_change_flags, int16]
} [packed]
usb_hub_status_flags = HUB_STATUS_LOCAL_POWER, HUB_STATUS_OVERCURRENT
usb_hub_change_flags = HUB_CHANGE_LOCAL_POWER, HUB_CHANGE_OVERCURRENT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# HID device class specific descriptions.
# https://www.usb.org/sites/default/files/documents/hid1_11.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/usbhid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/hid.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_hid.c
# Connected HID devices are known to create the following /dev/ files:
# /dev/hidraw#, /dev/usb/hiddev# and /dev/input/event#.
resource fd_usb_hid[fd_usb]
syz_usb_connect$hid(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_hid], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_hid (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$hid(fd fd_usb_hid, descs ptr[in, vusb_descriptors_hid], resps ptr[in, vusb_responses_hid]) (timeout[300], remote_cover)
# idVendor and idProduct are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor_hid {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 64, array[usb_config_descriptor_hid, 1]]
} [packed]
usb_config_descriptor_hid {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_hid, 1]]
} [packed]
usb_interface_descriptor_hid {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_HID, int8], const[USB_INTERFACE_SUBCLASS_BOOT, int8], flags[usb_hid_protocols, int8], usb_hid_descriptor_hid, usb_endpoint_descriptors_hid]
} [packed]
usb_hid_protocols = USB_INTERFACE_PROTOCOL_KEYBOARD, USB_INTERFACE_PROTOCOL_MOUSE
usb_endpoint_descriptors_hid {
in usb_endpoint_descriptor_hid_in
out array[usb_endpoint_descriptor_hid_out, 0:1]
} [packed]
usb_endpoint_descriptor_hid_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_IN_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_hid_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_OUT_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_HID_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_HID_IN_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_HID_OUT_ADDRESS (2)
vusb_descriptors_hid {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
# For unknown reasons these are requested as USB_TYPE_STANDARD and not as USB_TYPE_CLASS.
# Linux doesn't request HID_DT_HID, but some hosts might do that.
HID_DT_REPORT ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]]
HID_DT_HID ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_HID, usb_hid_descriptor_hid]]
} [packed]
vusb_responses_hid {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
HID_REQ_GET_REPORT ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_REPORT, array[int8, 0:256]]]
HID_REQ_GET_PROTOCOL ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_PROTOCOL, int8]]
} [packed]
# USB HID specifications allows for multiple report and physical descriptors
# to be present, but I don't see any support for them in the Linux kernel,
# except for a single report descriptor.
usb_hid_descriptor_hid {
bLength len[parent, int8]
bDescriptorType const[HID_DT_HID, int8]
bcdHID int16
bCountryCode int8
bNumDescriptors const[1, int8]
report_desc usb_hid_class_descriptor_report
} [packed]
usb_hid_class_descriptor_report {
bDescriptorType const[HID_DT_REPORT, int8]
wDescriptorLength int16[0:HID_MAX_DESCRIPTOR_SIZE]
} [packed]
# TODO: it's hard to describe the REPORT descriptor structure via syzkaller
# descriptions, so consider generating it in Go code.
# TODO: the length of REPORT descriptor must match the value in HID descriptor.
# TODO: there are vendor specific REPORT descriptor formats (Logitech HID++).
# Linux HID stack doesn't support long items.
hid_descriptor_report {
items array[hid_report_item_short]
} [packed]
type hid_report_item_short_012_t[TYPE, TAGS] {
bSize len[data, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 0:2]
} [packed]
type hid_report_item_short_4_t[TYPE, TAGS] {
bSize const[3, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 4]
} [packed]
type hid_report_item_short_t[TYPE, TAGS] [
item_012 hid_report_item_short_012_t[TYPE, TAGS]
item_4 hid_report_item_short_4_t[TYPE, TAGS]
] [varlen]
hid_report_item_short [
main hid_report_item_short_t[HID_ITEM_TYPE_MAIN, hid_report_item_main_tags]
global hid_report_item_short_t[HID_ITEM_TYPE_GLOBAL, hid_report_item_global_tags]
local hid_report_item_short_t[HID_ITEM_TYPE_LOCAL, hid_report_item_local_tags]
] [varlen]
hid_report_item_main_tags = HID_MAIN_ITEM_TAG_INPUT, HID_MAIN_ITEM_TAG_OUTPUT, HID_MAIN_ITEM_TAG_FEATURE, HID_MAIN_ITEM_TAG_BEGIN_COLLECTION, HID_MAIN_ITEM_TAG_END_COLLECTION
hid_report_item_global_tags = HID_GLOBAL_ITEM_TAG_USAGE_PAGE, HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT, HID_GLOBAL_ITEM_TAG_UNIT, HID_GLOBAL_ITEM_TAG_REPORT_SIZE, HID_GLOBAL_ITEM_TAG_REPORT_ID, HID_GLOBAL_ITEM_TAG_REPORT_COUNT, HID_GLOBAL_ITEM_TAG_PUSH, HID_GLOBAL_ITEM_TAG_POP
hid_report_item_local_tags = HID_LOCAL_ITEM_TAG_USAGE, HID_LOCAL_ITEM_TAG_USAGE_MINIMUM, HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX, HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM, HID_LOCAL_ITEM_TAG_STRING_INDEX, HID_LOCAL_ITEM_TAG_STRING_MINIMUM, HID_LOCAL_ITEM_TAG_STRING_MAXIMUM, HID_LOCAL_ITEM_TAG_DELIMITER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# PRINTER device class specific descriptions.
# https://www.usb.org/sites/default/files/usbprint11a021811.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/class/usblp.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/printer.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_printer.c
# Connected PRINTER devices are known to create the following /dev/ files:
# /dev/usb/lp#.
# TODO: write descriptions for those.
# drivers/usb/class/usblp.c
define USBLP_REQ_GET_ID 0x00
define USBLP_REQ_GET_STATUS 0x01
define USBLP_REQ_RESET 0x02
define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00
define USBLP_FIRST_PROTOCOL 1
define USBLP_LAST_PROTOCOL 3
resource fd_usb_printer[fd_usb]
syz_usb_connect$printer(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_printer], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_printer (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$printer(fd fd_usb_printer, descs ptr[in, vusb_descriptors_printer], resps ptr[in, vusb_responses_printer]) (timeout[300], remote_cover)
usb_device_descriptor_printer {
inner usb_device_descriptor_t[0, 0, 0, 0x525, 0xa4a8, 64, array[usb_config_descriptor_printer, 1]]
} [packed]
usb_config_descriptor_printer {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_printer, 1]]
} [packed]
usb_interface_descriptor_printer {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_PRINTER, int8], const[1, int8], int8[USBLP_FIRST_PROTOCOL:USBLP_LAST_PROTOCOL], void, usb_endpoint_descriptors_printer]
} [packed]
usb_endpoint_descriptors_printer {
in usb_endpoint_descriptor_printer_out
out array[usb_endpoint_descriptor_printer_in, 0:1]
} [packed]
usb_endpoint_descriptor_printer_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_OUT_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_printer_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_IN_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_PRINTER_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_PRINTER_OUT_ADDRESS (1)
define USB_ENDPOINT_PRINTER_IN_ADDRESS (2 | USB_DIR_IN)
vusb_descriptors_printer {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_printer {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USBLP_REQ_GET_ID ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_ID, usb_printer_get_id_response]]
USBLP_REQ_GET_STATUS ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_STATUS, int8]]
USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, int8]]
} [packed]
usb_printer_get_id_response {
length len[id, int16be]
id array[int8, 0:256]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC ECM (Ethernet) device class specific descriptions.
# https://www.usb.org/document-library/class-definitions-communication-devices-12
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ecm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/u_ether.c
# Connected CDC ECM devices are known to create usbN network interfaces.
# TODO: write descriptions for those.
resource fd_usb_cdc_ecm[fd_usb]
syz_usb_connect$cdc_ecm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ecm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ecm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ecm(fd fd_usb_cdc_ecm, descs ptr[in, vusb_descriptors_cdc_ecm], resps ptr[in, vusb_responses_cdc_ecm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ecm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ecm, 1]]
} [packed]
usb_config_descriptor_cdc_ecm {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_cdc_ecm, 1]]
} [packed]
# Per specification CDC ECM devices have two interfaces (control and data),
# but here we're merging them into one for simplicity since Linux supports that.
usb_interface_descriptor_cdc_ecm {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[2:3], const[USB_CLASS_COMM, int8], const[USB_CDC_SUBCLASS_ETHERNET, int8], const[USB_CDC_PROTO_NONE, int8], usb_cdc_header_ecm, usb_endpoint_descriptors_cdc_ecm]
} [packed]
usb_endpoint_descriptors_cdc_ecm {
notify array[usb_endpoint_descriptor_cdc_ecm_notify, 0:1]
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
usb_endpoint_descriptor_cdc_ecm_notify {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_IN_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_OUT_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_OUT_ADDRESS (3)
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L155
usb_cdc_header_ecm {
union usb_cdc_union_desc_t[0, 0]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
other array[usb_cdc_header_ecm_other, 0:6]
} [packed]
usb_cdc_header_ecm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
ncm usb_cdc_ncm_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
usb_cdc_header_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_HEADER_TYPE, int8]
bcdCDC int16
} [packed]
usb_cdc_call_mgmt_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_CALL_MANAGEMENT_TYPE, int8]
bmCapabilities flags[usb_cdc_call_mgmt_caps, int8]
bDataInterface int8
} [packed]
usb_cdc_call_mgmt_caps = USB_CDC_CALL_MGMT_CAP_CALL_MGMT, USB_CDC_CALL_MGMT_CAP_DATA_INTF
usb_cdc_acm_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ACM_TYPE, int8]
bmCapabilities flags[usb_cdc_acm_caps, int8]
} [packed]
usb_cdc_acm_caps = USB_CDC_COMM_FEATURE, USB_CDC_CAP_LINE, USB_CDC_CAP_BRK, USB_CDC_CAP_NOTIFY
type usb_cdc_union_desc_t[MASTER, SLAVE] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_UNION_TYPE, int8]
bMasterInterface0 const[MASTER, int8]
bSlaveInterface0 const[SLAVE, int8]
slave_interfaces array[int8, 0:6]
} [packed]
usb_cdc_country_functional_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_COUNTRY_TYPE, int8]
iCountryCodeRelDate int8
wCountyCode0 int16
country_codes array[int16, 0:6]
} [packed]
usb_cdc_network_terminal_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NETWORK_TERMINAL_TYPE, int8]
bEntityId int8
iName int8
bChannelIndex int8
bPhysicalInterface int8
} [packed]
usb_cdc_ether_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ETHERNET_TYPE, int8]
iMACAddress const[1, int8]
bmEthernetStatistics int32
wMaxSegmentSize int16
wNumberMCFilters int16
bNumberPowerFilters int8
} [packed]
usb_cdc_dmm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_DMM_TYPE, int8]
bcdVersion int16
wMaxCommand int16
} [packed]
usb_cdc_mdlm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_TYPE, int8]
bcdVersion int16
bGUID usb_cdc_ecm_mbm_guid
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L61
usb_cdc_ecm_mbm_guid {
id0 const[0x14f5e048ba817a3, int64]
id1 const[0x2a397ecbffc007a6, int64]
} [packed]
usb_cdc_mdlm_detail_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_DETAIL_TYPE, int8]
bGuidDescriptorType int8
bDetailData array[int8, 0:256]
} [packed]
usb_cdc_obex_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_OBEX_TYPE, int8]
bcdVersion int16
} [packed]
usb_cdc_ncm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NCM_TYPE, int8]
bcdNcmVersion int16
bmNetworkCapabilities flags[usb_cdc_ncm_ncaps, int8]
} [packed]
usb_cdc_ncm_ncaps = USB_CDC_NCM_NCAP_ETH_FILTER, USB_CDC_NCM_NCAP_NET_ADDRESS, USB_CDC_NCM_NCAP_ENCAP_COMMAND, USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE, USB_CDC_NCM_NCAP_CRC_MODE, USB_CDC_NCM_NCAP_NTB_INPUT_SIZE
usb_cdc_mbim_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_TYPE, int8]
bcdMBIMVersion int16
wMaxControlMessage int16
bNumberFilters int8
bMaxFilterSize int8
wMaxSegmentSize int16
bmNetworkCapabilities int8
} [packed]
usb_cdc_mbim_extended_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_EXTENDED_TYPE, int8]
bcdMBIMExtendedVersion int16
bMaxOutstandingCommandMessages int8
wMTU int16
} [packed]
vusb_descriptors_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
usb_cdc_ecm_mac {
# This is a UTF16 encoded string "424242424242".
data0 const[0x3400320034003200, int64be]
data1 const[0x3400320034003200, int64be]
data2 const[0x3400320034003200, int64be]
} [packed]
vusb_responses_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC NCM class specific descriptions.
# CDC NCM is based on CDC ECM, so some of the descriptions are reused.
# https://www.usb.org/document-library/network-control-model-devices-specification-v10-and-errata-and-adopters-agreement
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ncm.c
resource fd_usb_cdc_ncm[fd_usb]
syz_usb_connect$cdc_ncm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ncm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ncm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ncm(fd fd_usb_cdc_ncm, descs ptr[in, vusb_descriptors_cdc_ncm], resps ptr[in, vusb_responses_cdc_ncm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ncm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ncm, 1]]
} [packed]
usb_config_descriptor_cdc_ncm {
inner usb_config_descriptor_t[const[1, int8], const[2, int8], usb_interface_descriptors_cdc_ncm]
} [packed]
usb_interface_descriptors_cdc_ncm {
control usb_interface_descriptor_fixed_t[0, CDC_NCM_COMM_ALTSETTING_NCM, 1, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, usb_cdc_header_ncm, usb_endpoint_descriptor_cdc_ecm_notify]
data_nop usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, void]
data usb_interface_descriptor_fixed_t[1, CDC_NCM_DATA_ALTSETTING_NCM, 2, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, usb_endpoint_descriptors_cdc_ncm_data]
} [packed]
usb_endpoint_descriptors_cdc_ncm_data {
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ncm.c#L798
usb_cdc_header_ncm {
union usb_cdc_union_desc_t[0, 1]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
ncm usb_cdc_ncm_desc
other array[usb_cdc_header_ncm_other, 0:6]
} [packed]
usb_cdc_header_ncm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
vusb_descriptors_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
vusb_responses_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_CDC_GET_NTB_PARAMETERS ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_PARAMETERS, usb_cdc_ncm_ntb_parameters]]
USB_CDC_GET_NTB_INPUT_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_INPUT_SIZE, int32]]
USB_CDC_GET_NTB_FORMAT ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_FORMAT, int16[0:1]]]
USB_CDC_GET_MAX_DATAGRAM_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_MAX_DATAGRAM_SIZE, int16]]
USB_CDC_GET_CRC_MODE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_CRC_MODE, int16[0:1]]]
} [packed]
usb_cdc_ncm_ntb_parameters {
wLength int16
bmNtbFormatsSupported int16
dwNtbInMaxSize int32
wNdpInDivisor int16
wNdpInPayloadRemainder int16
wNdpInAlignment int16
wPadding1 int16
dwNtbOutMaxSize int32
wNdpOutDivisor int16
wNdpOutPayloadRemainder int16
wNdpOutAlignment int16
wNtbOutMaxDatagrams int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC1 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1_legacy.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
# TODO: find out which /dev/ files are created by connected UAC1 devices and add descriptions for those.
resource fd_usb_uac1[fd_usb]
syz_usb_connect$uac1(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac1], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac1 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac1(fd fd_usb_uac1, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac1 {
inner usb_device_descriptor_t[0, 0, 0, 0x1d6b, 0x101, 64, array[usb_config_descriptor_uac1, 1]]
} [packed]
usb_config_descriptor_uac1 {
inner usb_config_descriptor_t[const[1, int8], const[3, int8], usb_interface_descriptors_uac1]
} [packed]
# TODO: control interface might have and optional interrupt endpoint.
usb_interface_descriptors_uac1 {
inner usb_interface_descriptors_uac1_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac1_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, 0, uac_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC uses IDs to make it possible for terminals and units to refer to each other.
# We don't have a way to describe this, so just use a limited number of ids.
type uac_id int8[1:6]
uac_control_iface_extra_descriptors {
header uac1_ac_header_descriptor
others array[uac_control_iface_extra_descriptor, 0:6]
} [packed]
uac1_ac_header_descriptor {
bLength const[UAC_DT_AC_HEADER_LENGTH, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdADC int16
wTotalLength len[uac_control_iface_extra_descriptors, int16]
bInCollection const[F_AUDIO_NUM_INTERFACES, int8]
# These must match interfaces numbers.
baInterfaceNr0 const[1, int8]
baInterfaceNr1 const[2, int8]
} [packed]
uac_control_iface_extra_descriptor [
input_terminal uac_input_terminal_descriptor
output_terminal uac1_output_terminal_descriptor
mixer_unit uac_mixer_unit_descriptor
selector_unit uac_selector_unit_descriptor
feature_unit uac_feature_unit_descriptor
processing_unit uac_processing_unit_descriptor
extension_unit uac_extension_unit_descriptor
] [varlen]
define F_AUDIO_NUM_INTERFACES 2
define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
uac_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bNrChannels int8
wChannelConfig int16
iChannelNames int8
iTerminal int8
} [packed]
# The following list contains input terminal types and inout terminal types.
uac_input_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_INPUT_TERMINAL_UNDEFINED, UAC_INPUT_TERMINAL_MICROPHONE, UAC_INPUT_TERMINAL_DESKTOP_MICROPHONE, UAC_INPUT_TERMINAL_PERSONAL_MICROPHONE, UAC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE, UAC_INPUT_TERMINAL_MICROPHONE_ARRAY, UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
# The following list contains output terminal types and inout terminal types.
uac_output_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_OUTPUT_TERMINAL_UNDEFINED, UAC_OUTPUT_TERMINAL_SPEAKER, UAC_OUTPUT_TERMINAL_HEADPHONES, UAC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO, UAC_OUTPUT_TERMINAL_DESKTOP_SPEAKER, UAC_OUTPUT_TERMINAL_ROOM_SPEAKER, UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER, UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
uac1_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
iTerminal int8
} [packed]
uac_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_selector_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_SELECTOR_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bControlSize len[bmaControls, int8]
bmaControls array[flags[uac_feature_unit_controls, int16], 1:6]
iFeature int8
} [packed]
uac_feature_unit_controls = UAC_FU_MUTE, UAC_FU_VOLUME, UAC_FU_BASS, UAC_FU_MID, UAC_FU_TREBLE, UAC_FU_GRAPHIC_EQUALIZER, UAC_FU_AUTOMATIC_GAIN, UAC_FU_DELAY, UAC_FU_BASS_BOOST, UAC_FU_LOUDNESS
uac_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_PROCESSING_UNIT, int8]
bUnitID uac_id
wProcessType flags[uac_processing_unit_types, int16]
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_processing_unit_types = UAC_PROCESS_UNDEFINED, UAC_PROCESS_UP_DOWNMIX, UAC_PROCESS_DOLBY_PROLOGIC, UAC_PROCESS_STEREO_EXTENDER, UAC_PROCESS_REVERB, UAC_PROCESS_CHORUS, UAC_PROCESS_DYN_RANGE_COMP
uac_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_EXTENSION_UNIT, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_iface_extra_descriptors {
others array[uac_as_iface_extra_descriptor, 0:6]
} [packed]
uac_as_iface_extra_descriptor [
as_header uac1_as_header_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
format_type_i_ext uac_format_type_i_ext_descriptor
] [varlen]
uac1_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bDelay int8
wFormatTag flags[uac_format_tags, int16]
} [packed]
uac_format_tags = UAC_FORMAT_TYPE_I_UNDEFINED, UAC_FORMAT_TYPE_I_PCM, UAC_FORMAT_TYPE_I_PCM8, UAC_FORMAT_TYPE_I_IEEE_FLOAT, UAC_FORMAT_TYPE_I_ALAW, UAC_FORMAT_TYPE_I_MULAW, UAC_FORMAT_TYPE_II_MPEG, UAC_FORMAT_TYPE_II_AC3
uac_usb_format_types_i = UAC_FORMAT_TYPE_I, UAC_FORMAT_TYPE_II, UAC_FORMAT_TYPE_III, UAC_FORMAT_TYPE_UNDEFINED
uac_format_type_i_continuous_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tLowerSamFreq array[int8, 0:3]
tUpperSamFreq array[int8, 0:3]
} [packed]
uac_format_type_i_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
uac_format_type_ii_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
uac_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
define USB_ENDPOINT_UAC1_AS_OUT_ADDRESS (1 | USB_DIR_OUT)
define USB_ENDPOINT_UAC1_AS_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_UAC1_AS_ATTRIBUTES (USB_ENDPOINT_SYNC_ADAPTIVE | USB_ENDPOINT_XFER_ISOC)
uac_iso_ep_attributes = USB_ENDPOINT_SYNCTYPE, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC
uac_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC_EP_GENERAL, int8]
bmAttributes flags[uac_iso_ep_attributes, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
vusb_descriptors_uac1 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_uac1 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
audio_UAC_GET_CUR ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_CUR, array[int8, 1:3]]]
audio_UAC_GET_MIN ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MIN, array[int8, 1:3]]]
audio_UAC_GET_MAX ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MAX, array[int8, 1:3]]]
audio_UAC_GET_RES ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_RES, array[int8, 1:4]]]
audio_UAC_GET_MEM ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MEM, array[int8, 3]]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC2 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac2.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac2[fd_usb]
syz_usb_connect$uac2(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac2], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac2 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac2(fd fd_usb_uac2, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac2 {
inner usb_device_descriptor_t[0, 0, 0, 0x41e, 0x3000, 64, array[usb_config_descriptor_uac2, 1]]
} [packed]
usb_config_descriptor_uac2 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac2_interface_assoc_descriptor, usb_interface_descriptors_uac2]
} [packed]
uac2_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[audio_function_category_types, int8]
bFunctionProtocol const[UAC_VERSION_2, int8]
iFunction int8
} [packed]
audio_function_category_types = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER
usb_interface_descriptors_uac2 {
inner usb_interface_descriptors_uac2_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac2_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_2, uac2_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptors {
header uac2_ac_header_descriptor
others array[uac2_control_iface_extra_descriptor, 0:6]
} [packed]
uac2_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bcdADC int16
bCategory flags[uac2_feature_unit_controls, int8]
wTotalLength len[uac2_control_iface_extra_descriptors, int16]
bmControls int8
} [packed]
uac2_feature_unit_controls = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER, uac_feature_unit_controls
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_as_iface_extra_descriptors {
others array[uac2_as_iface_extra_descriptor, 0:6]
} [packed]
uac2_as_iface_extra_descriptor [
as_header uac2_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
uac2_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int8
bFormatType flags[uac_usb_format_types_i, int8]
bmFormats flags[uac_format_tags, int32]
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
} [packed]
b_sub_slot_sizes = 1, 2, 3, 4
uac2_format_type_i_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize flags[b_sub_slot_sizes, int8]
bBitResolution int8
} [packed]
uac2_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac_format_type_ii_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bHeaderLength int8
bSideBandProtocol int8
} [packed]
uac_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac2_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubtype const[UAC_EP_GENERAL, int8]
bmAttributes flags[csep_bm_attributes, int8]
bmControls flags[csep_bm_controls, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
csep_bm_attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, UAC_EP_CS_ATTR_PITCH_CONTROL, UAC_EP_CS_ATTR_FILL_MAX
csep_bm_controls = UAC2_CONTROL_PITCH, UAC2_CONTROL_DATA_OVERRUN, UAC2_CONTROL_DATA_UNDERRUN
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptor [
input_terminal uac2_input_terminal_descriptor
output_terminal uac2_output_terminal_descriptor
mixer_unit uac2_mixer_unit_descriptor
selector_unit uac2_clock_selector_descriptor
feature_unit uac2_feature_unit_descriptor
processing_unit uac2_processing_unit_descriptor
extension_unit uac2_extension_unit_descriptor
effect_unit uac2_effect_unit_descriptor
sample_rate uac2_sample_rate_descriptor
source_unit uac2_clock_source_descriptor
multiply_unit uac2_clock_multiplier_descriptor
] [varlen]
uac2_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
bmControls int8
iTerminal int8
} [packed]
uac2_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal int8
bSourceID uac_id
bCSourceID int8
bmControls int16
iTerminal int8
} [packed]
uac2_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Figure out if bmControls and iClockSelector should be a part of this structure.
uac2_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
# TODO: Verify coverage.
uac2_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_PROCESSING_UNIT_V2, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_processing_unit_types = UAC2_PROCESS_UNDEFINED, UAC2_PROCESS_UP_DOWNMIX, UAC2_PROCESS_DOLBY_PROLOCIC, UAC2_PROCESS_STEREO_EXTENDER
uac2_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_EXTENSION_UNIT_V2, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Verify coverage.
uac2_effect_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_EFFECT_UNIT, int8]
bUnitID uac_id
wEffectType flags[uac2_effect_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_effect_unit_types = UAC2_EFFECT_UNDEFINED, UAC2_EFFECT_PARAM_EQ, UAC2_EFFECT_REVERB, UAC2_EFFECT_MOD_DELAY, UAC2_EFFECT_DYN_RANGE_COMP
uac2_sample_rate_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_SAMPLE_RATE_CONVERTER, int8]
bUnitID uac_id
wProcessType flags[uac2_processing_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_feature_unit_controls, int16], 1:6]
} [packed]
uac2_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac2_clock_bmattribute_types, int8]
bmControls int8
bAssocTerminal int8
iClockSource flags[uac2_clock_source_types, int8]
} [packed]
uac2_clock_bmattribute_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_source_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int8
iClockMultiplier int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC3 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac3.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac3[fd_usb]
syz_usb_connect$uac3(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac3], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac3 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac3(fd fd_usb_uac3, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac3 {
inner usb_device_descriptor_t[0, 0, 0, 0x582, 0x582, 64, array[usb_config_descriptor_uac3, 1]]
} [packed]
usb_config_descriptor_uac3 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac3_interface_assoc_descriptor, usb_interface_descriptors_uac3]
} [packed]
uac3_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[uac3_all_subclasses, int8]
bFunctionProtocol const[UAC_VERSION_3, int8]
iFunction int8
} [packed]
usb_interface_descriptors_uac3 {
inner usb_interface_descriptors_uac3_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac3_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_3, uac3_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptors {
header uac3_ac_header_descriptor
others array[uac3_control_iface_extra_descriptor, 0:6]
} [packed]
uac3_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bCategory flags[uac3_feature_unit_controls, int8]
wTotalLength len[uac3_control_iface_extra_descriptors, int16]
bmControls int32
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_as_iface_extra_descriptors {
others array[uac3_as_iface_extra_descriptor, 0:6]
} [packed]
uac3_as_iface_extra_descriptor [
as_header uac3_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
# TODO: Figure out how wClusterDescrID is used in the kernel.
uac3_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int32
wClusterDescrID int16
bmFormats flags[uac_format_tags, int64]
bSubslotSize int8
bBitResolution int8
bmAuxProtocols int16
bControlSize int8
} [packed]
uac3_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC3_CS_ENDPOINT, int8]
bmControls int32
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptor [
input_terminal uac3_input_terminal_descriptor
output_terminal uac3_output_terminal_descriptor
mixer_unit uac3_mixer_unit_descriptor
selector_unit uac3_clock_selector_descriptor
source_unit uac3_clock_source_descriptor
multiply_unit uac3_clock_multiplier_descriptor
feature_unit uac3_feature_unit_descriptor
processing_unit uac3_processing_unit_descriptor
extension_unit uac3_extension_unit_descriptor
power_domain uac3_power_domain_descriptor
cluster_info_segment uac3_cluster_information_segment_descriptor
# Only cluster information segment is currently used in the kernel.See: sound/usb/stream.c
# cluster_segment uac3_cluster_segment_descriptor
# cluster_end_segment uac3_cluster_end_segment_descriptor
# The following units are not yet supported by the kernel.
# See audio_validators[] in sound/usb/validate.c:
# effect_unit uac3_effect_unit_descriptor
# sample_rate uac3_sample_rate_descriptor
# connectors_unit uac3_connectors_unit_descriptor
# extended_term_unit uac3_extended_terminal_unit
] [varlen]
uac3_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bmControls int32
wClusterDescrID int16
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
bCSourceID int8
bmControls int32
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac3_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
uac3_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac3_clock_bmattribute_types, int8]
bmControls int32
bReferenceTerminal int8
wClockSourceStr int16
} [packed]
uac3_clock_bmattribute_types = UAC3_CLOCK_SOURCE_TYPE_EXT, UAC3_CLOCK_SOURCE_TYPE_INT, UAC3_CLOCK_SOURCE_ASYNC, UAC3_CLOCK_SOURCE_SYNCED_TO_SOF
uac3_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int32
wCMultiplierDescrStr int16
} [packed]
uac3_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_feature_unit_controls, int32], 1:6]
} [packed]
uac3_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_PROCESSING_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_processing_unit_types = UAC3_PROCESS_UNDEFINED, UAC3_PROCESS_UP_DOWNMIX, UAC3_PROCESS_STEREO_EXTENDER, UAC3_PROCESS_MULTI_FUNCTION
uac3_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_EXTENSION_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_power_domain_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_POWER_DOMAIN, int8]
bPowerDomainID int8
waRecoveryTime1 int16
waRecoveryTime2 int16
bNrEntities int8
baEntityID array[int8, 0:8]
} [packed]
uac3_cluster_information_segment_descriptor {
bLength len[parent, int16]
bSegmentType const[UAC3_CHANNEL_INFORMATION, int8]
bChPurpose flags[uac3_cluster_channel_purposes, int8]
bChRelationship flags[uac3_cluster_channel_relationships, int8]
bChGroupID int8
} [packed]
uac3_cluster_channel_purposes = UAC3_PURPOSE_UNDEFINED, UAC3_PURPOSE_GENERIC_AUDIO, UAC3_PURPOSE_VOICE, UAC3_PURPOSE_SPEECH, UAC3_PURPOSE_AMBIENT, UAC3_PURPOSE_REFERENCE, UAC3_PURPOSE_ULTRASONIC, UAC3_PURPOSE_VIBROKINETIC, UAC3_PURPOSE_NON_AUDIO
uac3_cluster_channel_relationships = UAC3_CH_RELATIONSHIP_UNDEFINED, UAC3_CH_MONO, UAC3_CH_LEFT, UAC3_CH_RIGHT, UAC3_CH_ARRAY, UAC3_CH_PATTERN_X, UAC3_CH_PATTERN_Y, UAC3_CH_PATTERN_A, UAC3_CH_PATTERN_B, UAC3_CH_PATTERN_M, UAC3_CH_PATTERN_S, UAC3_CH_FRONT_LEFT, UAC3_CH_FRONT_RIGHT, UAC3_CH_FRONT_CENTER, UAC3_CH_FRONT_LEFT_OF_CENTER, UAC3_CH_FRONT_RIGHT_OF_CENTER, UAC3_CH_FRONT_WIDE_LEFT, UAC3_CH_FRONT_WIDE_RIGHT, UAC3_CH_SIDE_LEFT, UAC3_CH_SIDE_RIGHT, UAC3_CH_SURROUND_ARRAY_LEFT, UAC3_CH_SURROUND_ARRAY_RIGHT, UAC3_CH_BACK_LEFT, UAC3_CH_BACK_RIGHT, UAC3_CH_BACK_CENTER, UAC3_CH_BACK_LEFT_OF_CENTER, UAC3_CH_BACK_RIGHT_OF_CENTER, UAC3_CH_BACK_WIDE_LEFT, UAC3_CH_BACK_WIDE_RIGHT, UAC3_CH_TOP_CENTER, UAC3_CH_TOP_FRONT_LEFT, UAC3_CH_TOP_FRONT_RIGHT, UAC3_CH_TOP_FRONT_CENTER, UAC3_CH_TOP_FRONT_LOC, UAC3_CH_TOP_FRONT_ROC, UAC3_CH_TOP_FRONT_WIDE_LEFT, UAC3_CH_TOP_FRONT_WIDE_RIGHT, UAC3_CH_TOP_SIDE_LEFT, UAC3_CH_TOP_SIDE_RIGHT, UAC3_CH_TOP_SURR_ARRAY_LEFT, UAC3_CH_TOP_SURR_ARRAY_RIGHT, UAC3_CH_TOP_BACK_LEFT, UAC3_CH_TOP_BACK_RIGHT, UAC3_CH_TOP_BACK_CENTER, UAC3_CH_TOP_BACK_LOC, UAC3_CH_TOP_BACK_ROC, UAC3_CH_TOP_BACK_WIDE_LEFT, UAC3_CH_TOP_BACK_WIDE_RIGHT, UAC3_CH_BOTTOM_CENTER, UAC3_CH_BOTTOM_FRONT_LEFT, UAC3_CH_BOTTOM_FRONT_RIGHT, UAC3_CH_BOTTOM_FRONT_CENTER, UAC3_CH_BOTTOM_FRONT_LOC, UAC3_CH_BOTTOM_FRONT_ROC, UAC3_CH_BOTTOM_FRONT_WIDE_LEFT, UAC3_CH_BOTTOM_FRONT_WIDE_RIGHT, UAC3_CH_BOTTOM_SIDE_LEFT, UAC3_CH_BOTTOM_SIDE_RIGHT, UAC3_CH_BOTTOM_SURR_ARRAY_LEFT, UAC3_CH_BOTTOM_SURR_ARRAY_RIGHT, UAC3_CH_BOTTOM_BACK_LEFT, UAC3_CH_BOTTOM_BACK_RIGHT, UAC3_CH_BOTTOM_BACK_CENTER, UAC3_CH_BOTTOM_BACK_LOC, UAC3_CH_BOTTOM_BACK_ROC, UAC3_CH_BOTTOM_BACK_WIDE_LEFT, UAC3_CH_BOTTOM_BACK_WIDE_RIGHT, UAC3_CH_LOW_FREQUENCY_EFFECTS, UAC3_CH_LFE_LEFT, UAC3_CH_LFE_RIGHT, UAC3_CH_HEADPHONE_LEFT, UAC3_CH_HEADPHONE_RIGHT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# This list consists of uac3_func_subclasses + uac3_badd_classes.
uac3_all_subclasses = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0, UAC3_FUNCTION_SUBCLASS_GENERIC_IO, UAC3_FUNCTION_SUBCLASS_HEADPHONE, UAC3_FUNCTION_SUBCLASS_SPEAKER, UAC3_FUNCTION_SUBCLASS_MICROPHONE, UAC3_FUNCTION_SUBCLASS_HEADSET, UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE
uac3_feature_unit_controls = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_DESKTOP_SPEAKER, UAC3_FUNCTION_HOME_THEATER, UAC3_FUNCTION_MICROPHONE, UAC3_FUNCTION_HEADSET, UAC3_FUNCTION_TELEPHONE, UAC3_FUNCTION_CONVERTER, UAC3_FUNCTION_SOUND_RECORDER, UAC3_FUNCTION_IO_BOX, UAC3_FUNCTION_MUSICAL_INSTRUMENT, UAC3_FUNCTION_PRO_AUDIO, UAC3_FUNCTION_AUDIO_VIDEO, UAC3_FUNCTION_CONTROL_PANEL, UAC3_FUNCTION_HEADPHONE, UAC3_FUNCTION_GENERIC_SPEAKER, UAC3_FUNCTION_HEADSET_ADAPTER, UAC3_FUNCTION_SPEAKERPHONE, UAC3_FUNCTION_OTHER
# TODO: Support uac3 badd profiles. See sound/usb/mixer.c: snd_usb_mixer_controls_badd()
# uac3_badd_endpoint_descriptor {
# inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
# } [packed]
#uac3_badd_maxsizes = UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# MIDI device class specific descriptions.
# https://www.usb.org/sites/default/files/midi10.pdf
# https://elixir.bootlin.com/linux/latest/source/sound/usb/midi.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_midi.c
syz_usb_connect$midi(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_midi], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
usb_device_descriptor_midi {
inner usb_device_descriptor_t[0, 0, 0, 0x1430, 0x474b, 64, array[usb_config_descriptor_midi, 1]]
} [packed]
usb_config_descriptor_midi {
inner usb_config_descriptor_t[const[1, int8], const[1, int8], usb_interface_descriptors_midi]
} [packed]
usb_interface_descriptors_midi {
inner usb_interface_descriptors_midi_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_midi_inner {
control usb_interface_descriptor_eps_array_t[const[0, int8], const[0, int8], const[USB_CLASS_AUDIO, int8], const[USB_SUBCLASS_MIDISTREAMING, int8], flags[uac_version_types, int8], array[usb_midi_iface_extra], array[usb_endpoint_descriptor_midi, 0:8]]
} [packed]
usb_endpoint_descriptor_midi {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], usb_ms_endpoint_descriptor]
} [packed]
midi_jack_type = USB_MS_EMBEDDED, USB_MS_EXTERNAL
uac_version_types = UAC_VERSION_1, UAC_VERSION_2, UAC_VERSION_3
usb_ms_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[USB_MS_GENERAL, int8]
bNumEmbMIDIJack len[baAssocJackID, int8]
baAssocJackID array[int8, 0:16]
} [packed]
usb_midi_iface_extra [
ms_header usb_ms_header_descriptor
midi_in_jack usb_midi_in_jack_descriptor
midi_out_jack usb_midi_out_jack_descriptor
] [varlen]
usb_ms_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdMSC int16
wTotalLength len[parent, int16]
} [packed]
usb_midi_in_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_IN_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
iJack int8
} [packed]
usb_midi_out_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_OUT_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
bNrInputPins len[pins, int8]
pins array[usb_midi_source_pin]
iJack int8
} [packed]
usb_midi_source_pin {
baSourceID int8
baSourcePin int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# ath9k driver specific descriptions.
include <drivers/net/wireless/ath/ath9k/htc_hst.h>
include <drivers/net/wireless/ath/ath9k/hif_usb.h>
define USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS (1)
define USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_IN_ADDRESS (3 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS (4)
define USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS (5)
define USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS (6)
resource fd_usb_ath9k[fd_usb]
syz_usb_connect_ath9k(speed const[USB_SPEED_HIGH], dev_len len[dev], dev ptr[in, usb_device_descriptor_ath9k], conn_descs const[0]) fd_usb_ath9k (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_ep_write$ath9k_ep1(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS], len bytesize[data], data ptr[in, ath9k_bulk_frame]) (timeout[300], remote_cover)
syz_usb_ep_write$ath9k_ep2(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS], len bytesize[data], data ptr[in, htc_frame]) (timeout[300], remote_cover)
usb_device_descriptor_ath9k {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xcf3, 0x9271, 0x108, array[usb_config_descriptor_ath9k, 1]]
} [packed]
usb_config_descriptor_ath9k {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_ath9k]
} [packed]
usb_interface_descriptor_ath9k {
iface usb_interface_descriptor_fixed_t[0, 0, 6, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_ath9k]
} [packed]
usb_endpoint_descriptors_ath9k {
bulk_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
int_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
bulk_extra1 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_extra2 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
} [packed]
define USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_ATH9K_INT_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
ath9k_bulk_frame {
packets array[ath9k_bulk_packet]
} [packed]
ath9k_bulk_packet {
pkt_len len[data, int16]
pkt_tag const[ATH_USB_RX_STREAM_MODE_TAG, int16]
data array[int8]
} [packed, align[4]]
htc_frame [
ready htc_ready_frame
conn_svc_rsp htc_conn_svc_rsp_frame
generic htc_generic_frame
] [varlen]
# This is actually wrong, as the driver is buggy and doesn't skip the header
# before processing the frame payload, but let's leave it like thise for now.
htc_ready_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_ready_msg
} [packed]
htc_ready_msg {
message_id const[HTC_MSG_READY_ID, int16be]
credits int16be
credit_size int16be
max_endpoints int8
pad int8
} [packed]
htc_conn_svc_rsp_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_conn_svc_rspmsg
} [packed]
htc_conn_svc_rspmsg {
message_id const[HTC_MSG_CONNECT_SERVICE_RESPONSE_ID, int16be]
service_id flags[htc_svcs, int16be]
status const[HTC_SERVICE_SUCCESS, int8]
endpoint_id int8
max_msg_len int16be
svc_meta_len int8
pad int8
} [packed]
htc_svcs = HTC_CTRL_RSVD_SVC, HTC_LOOPBACK_RSVD_SVC, WMI_CONTROL_SVC, WMI_BEACON_SVC, WMI_CAB_SVC, WMI_UAPSD_SVC, WMI_MGMT_SVC, WMI_DATA_VO_SVC, WMI_DATA_VI_SVC, WMI_DATA_BE_SVC, WMI_DATA_BE_SVC
htc_generic_frame {
endpoint_id int8[0:8]
flags flags[htc_frame_flags, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload array[int8, 0:256]
} [packed]
htc_frame_flags = HTC_FLAGS_RECV_TRAILER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Assorted driver-specific descriptions of generic syz_* calls' variants.
# Generic calls such as syz_usb_connect() and syz_usb_control_io() should be enough
# (in theory) to emulate a proper device and finish driver probes without a hitch.
# However, there are cases when syzkaller fails to come up with correct inputs to achieve it.
# Use fixed descriptors to quickly pass through probe() to access select drivers' post-probe functionality.
# It is important to note that, one way or another, drivers in question require multiple control requests
# between a driver and a device processed during probe(). Descriptions below do not deal with specific
# CTRL requests as such (except for basic information included in vusb_responses_XXX). Instead, rely on
# seeds, created both manually and with syzkaller's help. For examples, see sys/linux/test/vusb_XXX.
# Common constants for endpoint descriptors.
define USB_ENDPOINT_BULK_ATTR (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_INT_ATTR (USB_ENDPOINT_XFER_INT)
define USB_FIXED_ENDPOINT_BULK_IN_ADDR (1 | USB_DIR_IN)
define USB_FIXED_ENDPOINT_BULK_OUT_ADDR (2)
define USB_FIXED_ENDPOINT_INT_IN_ADDR (3 | USB_DIR_IN)
define USB_RECIP_DEVICE 0x00
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# rtl8150 driver specific descriptions.
resource fd_usb_rtl8150[fd_usb]
syz_usb_connect$rtl8150(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_rtl8150], conn_descs const[0]) fd_usb_rtl8150 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$rtl8150(fd fd_usb_rtl8150, descs ptr[in, vusb_descriptors_rtl8150], resps ptr[in, vusb_responses_rtl8150]) (timeout[300], remote_cover)
usb_device_descriptor_rtl8150 {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xbda, 0x8150, 0, array[usb_config_descriptor_rtl8150, 1]]
} [packed]
usb_config_descriptor_rtl8150 {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_rtl8150]
} [packed]
usb_interface_descriptor_rtl8150 {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_rtl8150]
} [packed]
usb_endpoint_descriptors_rtl8150 {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
RTL8150_REQ_GET_REGS ptr[in, vusb_response_t[RTL8150_REQT_READ, RTL8150_REQ_GET_REGS, array[int8, 0:6]]]
RTL8150_REQ_SET_REGS ptr[in, vusb_response_t[RTL8150_REQT_WRITE, RTL8150_REQ_SET_REGS, array[int8, 0:6]]]
} [packed]
define RTL8150_REQ_GET_REGS 0x05
define RTL8150_REQ_SET_REGS 0x05
define RTL8150_REQT_READ 0xc0
define RTL8150_REQT_WRITE 0x40
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# sierra_net driver specific descriptions.
resource fd_usb_sierra_net[fd_usb]
syz_usb_connect$sierra_net(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_sierra_net], conn_descs const[0]) fd_usb_sierra_net (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$sierra_net(fd fd_usb_sierra_net, descs ptr[in, vusb_descriptors_sierra_net], resps ptr[in, vusb_responses_sierra_net]) (timeout[300], remote_cover)
usb_device_descriptor_sierra_net {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x1199, 0x68a3, 0, array[usb_config_descriptor_sierra_net, 1]]
} [packed]
usb_config_descriptor_sierra_net {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_sierra_net]
} [packed]
usb_interface_descriptor_sierra_net {
iface usb_interface_descriptor_fixed_t[7, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_sierra_net]
} [packed]
# sierra_net driver does not expect fixed ep addresses, so refrain from being too specific here.
# As long as we ensure there are 3 endpoints, 2 bulk and 1 int, syzkaller should figure it out.
usb_endpoint_descriptors_sierra_net {
bulk_in usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
bulk_out usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
status usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_INT_ATTR, int8], void]
} [packed]
vusb_descriptors_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_CDC_GET_ENCAPSULATED_RESPONSE ptr[in, vusb_response_t[SIERRA_CMD_TYPE_IN, USB_CDC_GET_ENCAPSULATED_RESPONSE, array[int8, 1024]]]
USB_CDC_SEND_ENCAPSULATED_COMMANDT ptr[in, vusb_response_t[SIERRA_CMD_TYPE_OUT, USB_CDC_SEND_ENCAPSULATED_COMMAND, array[int8, 0:4]]]
} [packed]
define SIERRA_CMD_TYPE_IN (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
define SIERRA_CMD_TYPE_OUT (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# lan78xx driver specific descriptions.
# While these syz_* variants noticably help with the probe() process, they are not enough.
# This is due to a high number of control requests expected between the driver and the device.
include <drivers/net/usb/smsc95xx.h>
resource fd_usb_lan78xx[fd_usb]
syz_usb_connect$lan78xx(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_lan78xx], conn_descs const[0]) fd_usb_lan78xx (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$lan78xx(fd fd_usb_lan78xx, descs ptr[in, vusb_descriptors_lan78xx], resps ptr[in, vusb_responses_lan78xx]) (timeout[300], remote_cover)
usb_device_descriptor_lan78xx {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x424, 0x7850, 0, array[usb_config_descriptor_lan78xx, 1]]
} [packed]
usb_config_descriptor_lan78xx {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_lan78xx]
} [packed]
usb_interface_descriptor_lan78xx {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_lan78xx]
} [packed]
usb_endpoint_descriptors_lan78xx {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_VENDOR_REQUEST_READ_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_READ_REGISTER, int32]]
USB_VENDOR_REQUEST_WRITE_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_OUT, USB_VENDOR_REQUEST_WRITE_REGISTER, int32]]
USB_VENDOR_REQUEST_GET_STATS ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_GET_STATS, array[int8, 47]]]
} [packed]
define LAN78XX_REG_TYPE_IN (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
define LAN78XX_REG_TYPE_OUT (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
]
|
| 191/2 |
2026/07/30 12:41 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 95817
output: 50
thoughts: 142
Thoughts: **Targeting Specific USB Devices**
Okay, so I'm digging into `syz_usb_connect`. It looks like the function wants a `speed`, device length (`dev_len`), device pointer (`dev`), and connection descriptors (`conn_descs`). Interesting. I see that I can use `syz_usb_connect(0, &AUTO, &AUTO, 0)` and syzkaller will automatically cook up a random `usb_device_descriptor` for me. But that's not what I'm after, I want to be more specific. I'm thinking I want to target devices like `si4713`, `au0828`, or `go7007`.
Hmm, wait a second... `si4713`... that's a radio driver, right? Right, it is. Let's see... I'll need to check the source code at `drivers/media/radio/si4713/radio-usb-si4713.c` to see how it's handled. Okay, now we are getting somewhere.
|
| 192/2 |
2026/07/30 12:41 |
tool |
read-file |
0m
Args: map[File:drivers/media/radio/si4713/radio-usb-si4713.c FirstLine:1 LineCount:100]
Results: map[Contents: 1: // SPDX-License-Identifier: GPL-2.0-only
2: /*
3: * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
4: * All rights reserved.
5: */
6:
7: /* kernel includes */
8: #include <linux/kernel.h>
9: #include <linux/module.h>
10: #include <linux/usb.h>
11: #include <linux/init.h>
12: #include <linux/slab.h>
13: #include <linux/input.h>
14: #include <linux/mutex.h>
15: #include <linux/i2c.h>
16: /* V4l includes */
17: #include <linux/videodev2.h>
18: #include <media/v4l2-common.h>
19: #include <media/v4l2-device.h>
20: #include <media/v4l2-ioctl.h>
21: #include <media/v4l2-event.h>
22: #include <linux/platform_data/media/si4713.h>
23:
24: #include "si4713.h"
25:
26: /* driver and module definitions */
27: MODULE_AUTHOR("Dinesh Ram <dinesh.ram@cern.ch>");
28: MODULE_DESCRIPTION("Si4713 FM Transmitter USB driver");
29: MODULE_LICENSE("GPL v2");
30:
31: /* The Device announces itself as Cygnal Integrated Products, Inc. */
32: #define USB_SI4713_VENDOR 0x10c4
33: #define USB_SI4713_PRODUCT 0x8244
34:
35: #define BUFFER_LENGTH 64
36: #define USB_TIMEOUT 1000
37: #define USB_RESP_TIMEOUT 50000
38:
39: /* USB Device ID List */
40: static const struct usb_device_id usb_si4713_usb_device_table[] = {
41: {USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT,
42: USB_CLASS_HID, 0, 0) },
43: { } /* Terminating entry */
44: };
45:
46: MODULE_DEVICE_TABLE(usb, usb_si4713_usb_device_table);
47:
48: struct si4713_usb_device {
49: struct usb_device *usbdev;
50: struct usb_interface *intf;
51: struct video_device vdev;
52: struct v4l2_device v4l2_dev;
53: struct v4l2_subdev *v4l2_subdev;
54: struct mutex lock;
55: struct i2c_adapter i2c_adapter;
56:
57: u8 *buffer;
58: };
59:
60: static inline struct si4713_usb_device *to_si4713_dev(struct v4l2_device *v4l2_dev)
61: {
62: return container_of(v4l2_dev, struct si4713_usb_device, v4l2_dev);
63: }
64:
65: static int vidioc_querycap(struct file *file, void *priv,
66: struct v4l2_capability *v)
67: {
68: struct si4713_usb_device *radio = video_drvdata(file);
69:
70: strscpy(v->driver, "radio-usb-si4713", sizeof(v->driver));
71: strscpy(v->card, "Si4713 FM Transmitter", sizeof(v->card));
72: usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
73: return 0;
74: }
75:
76: static int vidioc_g_modulator(struct file *file, void *priv,
77: struct v4l2_modulator *vm)
78: {
79: struct si4713_usb_device *radio = video_drvdata(file);
80:
81: return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_modulator, vm);
82: }
83:
84: static int vidioc_s_modulator(struct file *file, void *priv,
85: const struct v4l2_modulator *vm)
86: {
87: struct si4713_usb_device *radio = video_drvdata(file);
88:
89: return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_modulator, vm);
90: }
91:
92: static int vidioc_s_frequency(struct file *file, void *priv,
93: const struct v4l2_frequency *vf)
94: {
95: struct si4713_usb_device *radio = video_drvdata(file);
96:
97: return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_frequency, vf);
98: }
99:
100: static int vidioc_g_frequency(struct file *file, void *priv,
]
|
| 193/2 |
2026/07/30 12:41 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 97860
output: 594
thoughts: 1090
Thoughts: **Navigating the USB Device Descriptor Maze**
Okay, so I'm looking at how to trigger this `si4713` device. It looks like the `USB_CLASS_HID` class matches. The `syz_usb_connect$hid` call *should* work if syzkaller is patching the vendor and product IDs. I need to make sure this call does patch the right ones, right?
I see that `syz_usb_connect$hid` uses `usb_device_descriptor_hid` where Go code patches those values. Can't easily check the Go code. But hold on... I could just manually specify the vendor/product IDs in the syzkaller program!
Wait... `syz_usb_connect$hid` takes a pointer to `usb_device_descriptor_hid`. The definition is: a structure with a nested `usb_device_descriptor_t`, where vendor and product are hardcoded to zero! That means they *are* being patched!
If I wanted to provide my own descriptor, I'd need to use the generic `syz_usb_connect` function. However, constructing a custom `usb_device_descriptor` with nested structures looks complicated, with nested `usb_config_descriptor`.
Aha! `&AUTO`! I can let syzkaller generate most of it and override specific fields. For example, I could override just vendor and product: `&AUTO={@inner={0, 0, 0, 0, 0, 0, 0, 0x10c4, 0x8244, 0, 0, 0, 0, 0, []}}`.
But... `usb_device_descriptor_t` is actually an alias for `usb_device_descriptor_verbose_t`. And that's where all the detailed structure is defined: all the individual values, bLength, bDescriptorType, and all the rest. And also nested `usb_config_descriptor_t`.
So, using `syz_usb_connect(0, &AUTO, &AUTO, 0)`, the `dev` argument is going to be `usb_device_descriptor`: a struct with a nested `usb_device_descriptor_t` with even further nested descriptors. Now, I *could* craft something complex like: `&AUTO={@inner={AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, 0x10c4, 0x8244, AUTO, AUTO, AUTO, AUTO, AUTO, [@inner={AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, [@inner={AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, [@inner={AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO}]}]}]}}`, but it looks way too cumbersome.
Wait... back to `syz_usb_connect$hid`, maybe it won't patch the `si4713` IDs because they are not in the patching list. I *could* verify if `si4713` is listed, but if not:
I could use `syz_usb_connect` and just override `idVendor` and `idProduct`. No hex strings, no need for complex nested structs! Use `&AUTO={@inner={AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, 0x10c4, 0x8244}}`. Yes, I'll go with this! Let's try it.
|
| 194/2 |
2026/07/30 12:41 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={@inner={AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, 0x10c4, 0x8244}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 195/2 |
2026/07/30 12:41 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 100463
output: 591
thoughts: 113
Thoughts: **Analyzing the USB Device Descriptor**
Okay, so I'm looking at this `usb_device_descriptor`. The first thing that jumps out at me is that it's *not* a union, but a struct. That's good. Now, I see the structure definition... it's `usb_device_descriptor { inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]] } [packed]`. With the array syntax. Hmmm, the size and structure are probably important here. Given the overall context, I should construct the AUTO fill for this structure. Therefore, the memory layout should be `&AUTO={{AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, 0x10c4, 0x8244}}`. I think that looks correct given the declaration.
|
| 196/2 |
2026/07/30 12:41 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, 0x10c4, 0x8244}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 197/2 |
2026/07/30 12:41 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 101386
output: 598
thoughts: 477
Thoughts: **Analyzing USB Device Descriptor Structure**
Okay, so I'm trying to figure out how these USB descriptors work, and it's clear that `AUTO` isn't going to cut it for flags. I need to dig deeper. Let's examine this `usb_device_descriptor_verbose_t` structure.
```
type usb_device_descriptor_verbose_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] {
bLength const[USB_DT_DEVICE_SIZE, int8]
bDescriptorType const[USB_DT_DEVICE, int8]
bcdUSB USB
bDeviceClass const[CLASS, int8]
bDeviceSubClass const[SUBCLASS, int8]
bDeviceProtocol const[PROTOCOL, int8]
bMaxPacketSize0 PACKET
idVendor const[VENDOR, int16]
idProduct const[PRODUCT, int16]
bcdDevice const[DEVICE, int16]
iManufacturer const[1, int8]
iProduct const[2, int8]
iSerialNumber const[3, int8]
bNumConfigurations len[configs, int8]
configs CFS
} [packed]
```
Alright, I see the fields. Now, let's look at how `usb_device_descriptor_t` is defined. Aha! I see the relationship now.
`type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[flags[usb_versions, int16], CLASS, SUBCLASS, PROTOCOL, flags[usb_device_max_packet_sizes, int8], VENDOR, PRODUCT, DEVICE, CFS]`
It looks like the `bcdUSB` field is actually a flag, representing USB version, and the `bMaxPacketSize0` field is another flag, indicating maximum packet size. Knowing this, I think I can safely use `0x200` for `bcdUSB` (for USB 2.0) and `64` for `bMaxPacketSize0`. Hopefully, this will get me a valid descriptor. I'll test it out with:
`&AUTO={{AUTO, AUTO, 0x200, AUTO, AUTO, AUTO, 64, 0x10c4, 0x8244}}`
|
| 198/2 |
2026/07/30 12:41 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{AUTO, AUTO, 0x200, AUTO, AUTO, AUTO, 64, 0x10c4, 0x8244}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 199/2 |
2026/07/30 12:41 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 103174
output: 610
thoughts: 257
Thoughts: **My Current Focus: Defining the Device Descriptor**
Okay, I've got it, I need to define the device descriptor. I almost missed some critical fields in the process, but I've reviewed the list. Let's make sure I hit all the necessary elements. There are 15 fields total and they are: `bLength`, `bDescriptorType`, `bcdUSB`, `bDeviceClass`, `bDeviceSubClass`, `bDeviceProtocol`, `bMaxPacketSize0`, `idVendor`, `idProduct`, `bcdDevice`, `iManufacturer`, `iProduct`, `iSerialNumber`, `bNumConfigurations`, and `configs`. Now, let's assemble this correctly. I can see that some of these have an AUTO value assigned to them and these will be derived by the system. All the other fields will be set to values as described.
So, the complete device descriptor is: `&AUTO={{AUTO, AUTO, 0x200, AUTO, AUTO, AUTO, 64, 0x10c4, 0x8244, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO}}`.
|
| 200/2 |
2026/07/30 12:42 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{AUTO, AUTO, 0x200, AUTO, AUTO, AUTO, 64, 0x10c4, 0x8244, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 201/2 |
2026/07/30 12:42 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 104309
output: 610
thoughts: 104
Thoughts: **Working Through the Configuration Issue**
Okay, so I'm looking at this `configs` variable and it's definitely an array. That immediately tells me I can't just use `AUTO` on its own for this particular case. It expects an array, and `AUTO` just isn't designed for array initialization. Let's see... the type is `array[usb_config_descriptor, 1]`. Right, a single-element array containing a `usb_config_descriptor`. Given that, an empty array `[]` should be perfectly acceptable to serve as a placeholder or to essentially suppress the automatic configuration. So, the correct substitution to get things working is: `&AUTO={{AUTO, AUTO, 0x200, AUTO, AUTO, AUTO, 64, 0x10c4, 0x8244, AUTO, AUTO, AUTO, AUTO, AUTO, []}}` . I am making an array of the proper size, with empty configuration info, thus suppressing the issue.
|
| 202/2 |
2026/07/30 12:42 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{AUTO, AUTO, 0x200, AUTO, AUTO, AUTO, 64, 0x10c4, 0x8244, AUTO, AUTO, AUTO, AUTO, AUTO, []}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 203/2 |
2026/07/30 12:42 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 105343
output: 629
thoughts: 585
Thoughts: **Deconstructing the `usb_config_descriptor`**
Okay, so I'm looking at `array[usb_config_descriptor, 1]`. That means I need exactly one element in the array. My first thought was `[{}]`, but then I remember `usb_config_descriptor` is a struct, and it has an `inner` field. Alright, let's dive into that `usb_config_descriptor` definition.
Looking at the structure, `usb_config_descriptor` contains `inner`, which itself looks like `usb_config_descriptor_ifaces_array_t[int8, array[usb_interface_descriptor, 1:4]]`. Okay, that's interesting. Then I see that `usb_config_descriptor_ifaces_array_t` is actually `usb_config_descriptor_t[NUM, len[interfaces, int8], IFS]`. And then `usb_config_descriptor_t` expands to `usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, void, IFS]`. Alright, this gives the underlying structure of the descriptor.
Finally, the breakdown: `usb_config_descriptor_verbose_t`... Right, so we have several fields: `bLength`, `bDescriptorType`, `wTotalLength`, `bNumInterfaces`, `bConfigurationValue`, `iConfiguration`, `bmAttributes`, `bMaxPower`, `extra`, and `interfaces`. The `extra` field is declared as `void`. My brain's screaming, '0 fields!', so I check to confirm the void definition. Yep, `void` takes zero fields. That means we have a total of nine fields.
Now let's see, that structure looks like:
1. `bLength` (AUTO)
2. `bDescriptorType` (AUTO)
3. `wTotalLength` (AUTO)
4. `bNumInterfaces` (AUTO)
5. `bConfigurationValue` (AUTO)
6. `iConfiguration` (AUTO)
7. `bmAttributes` (AUTO)
8. `bMaxPower` (AUTO)
9. `interfaces` (array)
So, based on this, I'll attempt building an instance that looks like `[{inner={AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, []}}]`. Let's see if this works.
|
| 204/2 |
2026/07/30 12:42 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{AUTO, AUTO, 0x200, AUTO, AUTO, AUTO, 64, 0x10c4, 0x8244, AUTO, AUTO, AUTO, AUTO, AUTO, [{{AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, []}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 205/2 |
2026/07/30 12:42 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 107113
output: 633
thoughts: 122
Thoughts: **Decoding the Configuration Attributes**
Okay, so I'm looking at `bmAttributes`. It's clearly a bitfield β a series of flags represented as `flags[usb_config_attributes, int8]`. That means I have to set a value. Diving into the options, `usb_config_attributes` contains the possibilities: `USB_CONFIG_ATT_ONE`, `USB_CONFIG_ATT_SELFPOWER`, `USB_CONFIG_ATT_WAKEUP`, and `USB_CONFIG_ATT_BATTERY`. Based on what I'm seeing here, a good initial approach is to use `0x80`, which corresponds to `USB_CONFIG_ATT_ONE`. This looks right, and here's how the resulting structure is configured: `[{inner={AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, 0x80, AUTO, []}}]`.
|
| 206/2 |
2026/07/30 12:42 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{AUTO, AUTO, 0x200, AUTO, AUTO, AUTO, 64, 0x10c4, 0x8244, AUTO, AUTO, AUTO, AUTO, AUTO, [{{AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, 0x80, AUTO, []}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 207/2 |
2026/07/30 12:42 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 108080
output: 648
thoughts: 671
Thoughts: **Analyzing USB Descriptor Structure with Syzkaller**
Okay, so I'm looking at how Syzkaller should handle USB descriptors, particularly with `AUTO`. Let's break this down. First, I'm checking the types. `bConfigurationValue` is `NUM`, an `int8`. `AUTO` should work fine here. The `usb_config_descriptor`'s structure confirms that `NUM` is indeed an `int8`.
`bNumInterfaces` is `IFSNUM`, also an `int8`, defined as the length of an interface array, so `AUTO` should also be applicable. `iConfiguration` and `bMaxPower` are also `int8`, so `AUTO` should apply here.
Now, let's revisit `usb_device_descriptor_verbose_t`. `bDeviceClass` is `const[CLASS, int8]`. Wait, the `usb_device_descriptor` is composed of an array of `usb_config_descriptor` with fields such as `bDeviceClass` in it. `CLASS` appears to be `0` (as it has to be). The `const` modifier here is what's throwing a wrench in things, right? `const` fields shouldn't take `AUTO`.
Okay, the crucial point is that `const` fields are treated differently. Syzkaller probably fills these with known values anyway; maybe I can provide a precise value or use `AUTO` but it sounds like I can't.
Looking closer, the error "wrong type *prog.IntType for AUTO" is key. It indicates that `AUTO` is being used where an `IntType` is expected but isn't allowed. However, inside a struct, `AUTO` should be perfectly acceptable for `IntType` fields, right? This is where the error stems from.
The error means that when an `IntType` is expected, I am NOT allowed to use `AUTO`.
To be safe, let's provide `0` for all the `AUTO` values which are integers, rather than rely on `AUTO` within structures as Syzkaller currently implements it. That should resolve this issue. In other words, if I'm not sure, I'll provide an explicit value.
|
| 208/2 |
2026/07/30 12:42 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, 0, [{{0, 0, 0, 0, 0, 0, 0x80, 0, []}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 209/2 |
2026/07/30 12:42 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 110021
output: 678
thoughts: 886
Thoughts: **Deconstructing the USB Interface Descriptor**
Okay, so I'm looking at this `interfaces` definition and it's an array of `usb_interface_descriptor` with a minimum of one element. Let's delve into what this `usb_interface_descriptor` actually *is*.
Right, so `usb_interface_descriptor` contains an `inner` field. This `inner` field is of type `usb_interface_descriptor_eps_array_t`. Let's unravel this type.
Following the chain, `usb_interface_descriptor_eps_array_t` is defined in terms of `usb_interface_descriptor_t`, which in turn leads us to `usb_interface_descriptor_verbose_t`. And here it is! This `usb_interface_descriptor_verbose_t` looks like the core of the structure. It has these key fields: `bLength`, `bDescriptorType`, `bInterfaceNumber`, `bAlternateSetting`, `bNumEndpoints`, `bInterfaceClass`, `bInterfaceSubClass`, `bInterfaceProtocol`, `iInterface`, `extra`, and `endpoints`. Wait a minute, did I just count eleven fields? Let me double-check. Yes, that's right, eleven fields.
So, initially, the `inner` field starts with default values, and the `extra` and `endpoints` arrays are empty. Thus my initial understanding is as follows: `[{inner={0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}]`.
Okay, now let's apply the *si4713* requirement; specifically, `USB_CLASS_HID` (which is `3`). Therefore, I need to modify `bInterfaceClass` to be `3`. Thus the updated result is now: `[{inner={0, 0, 0, 0, 0, 3, 0, 0, 0, [], []}}]`.
|
| 210/2 |
2026/07/30 12:43 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, 0, [{{0, 0, 0, 0, 0, 0, 0x80, 0, [{{0, 0, 0, 0, 0, 3, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 211/2 |
2026/07/30 12:43 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 112185
output: 48
thoughts: 1077
Thoughts: **Analyzing USB Descriptor Construction for HID Device Interaction**
Okay, let's break this down. My initial thought was about how the `usb_interface_descriptor` is structured. Specifically, the fact that `usb_interface_descriptor_eps_array_t`'s `CLASS` field is a `const[0, int8]` is crucial. This means the `bInterfaceClass` *must* be set to 0. Therefore, any `syz_usb_connect` calls that utilize the basic `usb_device_descriptor` will *always* have a `bInterfaceClass` of 0. That's a constraint I need to keep in mind.
Now, the `syz_usb_connect$hid` call, however, uses `usb_device_descriptor_hid`, which sets the `bInterfaceClass` to `USB_CLASS_HID` (3). This is a potential route. Digging deeper into `usb_device_descriptor_hid` shows that it is comprised of an `inner` field which is `usb_device_descriptor_t` which includes `usb_config_descriptor_hid`. This is promising. The `usb_config_descriptor_hid` contains a `usb_interface_descriptor_hid` structure. The `usb_interface_descriptor_hid` is where the HID-specific data resides. Specifically, the `bInterfaceClass` and its associated values are key.
The ideal scenario would be to modify the `idVendor` and `idProduct` fields within the `usb_device_descriptor_hid` struct to target my desired device. The syntax for this might be something like `&AUTO={@inner={AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, AUTO, 0x10c4, 0x8244}}`. However, `usb_device_descriptor_hid` is actually a struct containing a *single* `inner` field of `usb_device_descriptor_t`. So, I'd have to specify all 15 fields of the `usb_device_descriptor_t` structure. This sounds like it might get unwieldy and error-prone.
So, let's explore if syzkaller automatically handles some of this for me. Does syzkaller already patch `idVendor` and `idProduct` when I use `syz_usb_connect$hid`, maybe to match a HID driver?
If it does, I can check if it patches to my target device. I wonder if it includes the `si4713`? No, it's very unlikely to hit it by chance, given the number of HID drivers. I remember `si4713` is a radio driver, but it registers as a USB HID device. That is very unusual. Let's look for other cases. How about `au0828`? That's a video driver, and its associated code base will have valuable information. Let's start by looking at `drivers/media/usb/au0828/au0828-core.c`.
|
| 212/2 |
2026/07/30 12:43 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:1 LineCount:100]
Results: map[Contents: 1: // SPDX-License-Identifier: GPL-2.0-or-later
2: /*
3: * Driver for the Auvitek USB bridge
4: *
5: * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
6: */
7:
8: #include "au0828.h"
9: #include "au8522.h"
10:
11: #include <linux/module.h>
12: #include <linux/slab.h>
13: #include <linux/videodev2.h>
14: #include <media/v4l2-common.h>
15: #include <linux/mutex.h>
16:
17: /* Due to enum tuner_pad_index */
18: #include <media/tuner.h>
19:
20: /*
21: * 1 = General debug messages
22: * 2 = USB handling
23: * 4 = I2C related
24: * 8 = Bridge related
25: * 16 = IR related
26: */
27: int au0828_debug;
28: module_param_named(debug, au0828_debug, int, 0644);
29: MODULE_PARM_DESC(debug,
30: "set debug bitmask: 1=general, 2=USB, 4=I2C, 8=bridge, 16=IR");
31:
32: static unsigned int disable_usb_speed_check;
33: module_param(disable_usb_speed_check, int, 0444);
34: MODULE_PARM_DESC(disable_usb_speed_check,
35: "override min bandwidth requirement of 480M bps");
36:
37: #define _AU0828_BULKPIPE 0x03
38: #define _BULKPIPESIZE 0xffff
39:
40: static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
41: u16 index);
42: static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
43: u16 index, unsigned char *cp, u16 size);
44:
45: /* USB Direction */
46: #define CMD_REQUEST_IN 0x00
47: #define CMD_REQUEST_OUT 0x01
48:
49: u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
50: {
51: u8 result = 0;
52:
53: recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, &result, 1);
54: dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, result);
55:
56: return result;
57: }
58:
59: u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
60: {
61: dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
62: return send_control_msg(dev, CMD_REQUEST_OUT, val, reg);
63: }
64:
65: static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
66: u16 index)
67: {
68: int status = -ENODEV;
69:
70: if (dev->usbdev) {
71:
72: /* cp must be memory that has been allocated by kmalloc */
73: status = usb_control_msg(dev->usbdev,
74: usb_sndctrlpipe(dev->usbdev, 0),
75: request,
76: USB_DIR_OUT | USB_TYPE_VENDOR |
77: USB_RECIP_DEVICE,
78: value, index, NULL, 0, 1000);
79:
80: status = min(status, 0);
81:
82: if (status < 0) {
83: pr_err("%s() Failed sending control message, error %d.\n",
84: __func__, status);
85: }
86:
87: }
88:
89: return status;
90: }
91:
92: static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
93: u16 index, unsigned char *cp, u16 size)
94: {
95: int status = -ENODEV;
96: mutex_lock(&dev->mutex);
97: if (dev->usbdev) {
98: status = usb_control_msg(dev->usbdev,
99: usb_rcvctrlpipe(dev->usbdev, 0),
100: request,
]
|
| 213/2 |
2026/07/30 12:43 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 115480
output: 50
thoughts: 48
Thoughts: **Analyzing the `au0828` Video Driver**
Okay, so `au0828` is a video driver. My initial instinct is to dig into the USB identification details to understand the specific hardware it's designed to support. So, my next thought is to head straight to the source code β specifically, `drivers/media/usb/au0828/au0828-cards.c`. That's where I'd expect to find the USB IDs meticulously listed. Understanding those IDs will give me the crucial insight I need to fully grasp the supported devices.
|
| 214/2 |
2026/07/30 12:43 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-cards.c FirstLine:310 LineCount:100]
Results: map[Contents: 310:
311: /* Into reset */
312: au0828_write(dev, REG_001, 0x0);
313: au0828_write(dev, REG_000, 0x0);
314: msleep(50);
315:
316: /* Bring power supply out of reset */
317: au0828_write(dev, REG_000, 0x80);
318: msleep(50);
319:
320: /* Bring xc5000 and au8522 out of reset (leave the
321: cs5340 in reset until needed) */
322: au0828_write(dev, REG_001, 0x02); /* xc5000 */
323: au0828_write(dev, REG_000, 0x80 | 0x20); /* PS + au8522 */
324:
325: msleep(250);
326: break;
327: case AU0828_BOARD_DVICO_FUSIONHDTV7:
328: /* GPIO's
329: * 6 - ?
330: * 8 - AU8522 Demodulator
331: * 9 - XC5000 Tuner
332: */
333:
334: /* Into reset */
335: au0828_write(dev, REG_003, 0x02);
336: au0828_write(dev, REG_002, 0xa0);
337: au0828_write(dev, REG_001, 0x0);
338: au0828_write(dev, REG_000, 0x0);
339: msleep(100);
340:
341: /* Out of reset */
342: au0828_write(dev, REG_003, 0x02);
343: au0828_write(dev, REG_002, 0xa0);
344: au0828_write(dev, REG_001, 0x02);
345: au0828_write(dev, REG_000, 0xa0);
346: msleep(250);
347: break;
348: }
349: }
350:
351: /* table of devices that work with this driver */
352: struct usb_device_id au0828_usb_id_table[] = {
353: { USB_DEVICE(0x2040, 0x7200),
354: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
355: { USB_DEVICE(0x2040, 0x7240),
356: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
357: { USB_DEVICE(0x0fe9, 0xd620),
358: .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
359: { USB_DEVICE(0x2040, 0x7210),
360: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
361: { USB_DEVICE(0x2040, 0x7217),
362: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
363: { USB_DEVICE(0x2040, 0x721b),
364: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
365: { USB_DEVICE(0x2040, 0x721e),
366: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
367: { USB_DEVICE(0x2040, 0x721f),
368: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
369: { USB_DEVICE(0x2040, 0x7280),
370: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
371: { USB_DEVICE(0x0fd9, 0x0008),
372: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
373: { USB_DEVICE(0x2040, 0x7201),
374: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
375: { USB_DEVICE(0x2040, 0x7211),
376: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
377: { USB_DEVICE(0x2040, 0x7281),
378: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
379: { USB_DEVICE(0x05e1, 0x0480),
380: .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
381: { USB_DEVICE(0x2040, 0x8200),
382: .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
383: { USB_DEVICE(0x2040, 0x7260),
384: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
385: { USB_DEVICE(0x2040, 0x7213),
386: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
387: { USB_DEVICE(0x2040, 0x7270),
388: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
389: { USB_DEVICE(0x2040, 0x72b0),
390: .driver_info = AU0828_BOARD_HAUPPAUGE_IMPACTVCBE },
391: { USB_DEVICE(0x2040, 0x72a0),
392: .driver_info = AU0828_BOARD_HAUPPAUGE_HVR1265 },
393: { },
394: };
395:
396: MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
]
|
| 215/2 |
2026/07/30 12:43 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 117735
output: 51
thoughts: 318
Thoughts: **USB Device ID Ponderings**
Okay, so I've got `au0828` with the specific ID `0x2040:0x7200`. My immediate thought is, does syzkaller have a predefined description for this device? Let me quickly scan `dev_video4linux.txt` and `vusb.txt` to see if it's already there. Nope, not in `vusb.txt`.
Alright, I could try using `syz_usb_connect(0, &AUTO, &AUTO, 0)`, and syzkaller *could* generate a random device descriptor. But that's not what I want. I need to nail down those `idVendor` and `idProduct` values. I know building a `usb_device_descriptor` manually is a pain. I could use `syz_usb_connect$hid`, but unfortunately the Go code patches prevent overriding `idVendor` and `idProduct`.
Hmm... what if I use `syz_usb_connect` and just feed it the raw bytes directly? No, that won't work, because `syz_usb_connect` expects a `usb_device_descriptor` struct.
Wait a minute... I could use `syz_usb_connect` with `&AUTO` and let syzkaller mutate it. That's a possibility. The problem is I want this to be deterministic, so random mutation isn't ideal.
Is there *any* other syzkaller primitive that would let me connect a USB device with these specific IDs? What about the `go7007` driver? Let me go look at `drivers/media/usb/go7007/go7007-usb.c` to see if that gives me any ideas.
|
| 216/2 |
2026/07/30 12:43 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1200 LineCount:100]
Results: map[Contents:1200: } else {
1201: u16 channel;
1202:
1203: /* read channel number from GPIO[1:0] */
1204: if (go7007_read_addr(go, 0x3c81, &channel))
1205: goto allocfail;
1206:
1207: channel &= 0x3;
1208: go->board_id = GO7007_BOARDID_ADLINK_MPG24;
1209: usb->board = board = &board_adlink_mpg24;
1210: go->board_info = &board->main_info;
1211: go->channel_number = channel;
1212: snprintf(go->name, sizeof(go->name),
1213: "Adlink PCI-MPG24, channel #%d",
1214: channel);
1215: }
1216: go7007_update_board(go);
1217: }
1218: }
1219:
1220: num_i2c_devs = go->board_info->num_i2c_devs;
1221:
1222: /* Probe the tuner model on the TV402U */
1223: if (go->board_id == GO7007_BOARDID_PX_TV402U) {
1224: /* Board strapping indicates tuner model */
1225: if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3,
1226: 1) < 0) {
1227: dev_err(go->dev, "GPIO read failed!\n");
1228: goto allocfail;
1229: }
1230: switch (go->usb_buf[0] >> 6) {
1231: case 1:
1232: go->tuner_type = TUNER_SONY_BTF_PG472Z;
1233: go->std = V4L2_STD_PAL;
1234: strscpy(go->name, "Plextor PX-TV402U-EU",
1235: sizeof(go->name));
1236: break;
1237: case 2:
1238: go->tuner_type = TUNER_SONY_BTF_PK467Z;
1239: go->std = V4L2_STD_NTSC_M_JP;
1240: num_i2c_devs -= 2;
1241: strscpy(go->name, "Plextor PX-TV402U-JP",
1242: sizeof(go->name));
1243: break;
1244: case 3:
1245: go->tuner_type = TUNER_SONY_BTF_PB463Z;
1246: num_i2c_devs -= 2;
1247: strscpy(go->name, "Plextor PX-TV402U-NA",
1248: sizeof(go->name));
1249: break;
1250: default:
1251: pr_debug("unable to detect tuner type!\n");
1252: break;
1253: }
1254: /* Configure tuner mode selection inputs connected
1255: * to the EZ-USB GPIO output pins */
1256: if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
1257: NULL, 0, 0) < 0) {
1258: dev_err(go->dev, "GPIO write failed!\n");
1259: goto allocfail;
1260: }
1261: }
1262:
1263: /* Print a nasty message if the user attempts to use a USB2.0 device in
1264: * a USB1.1 port. There will be silent corruption of the stream. */
1265: if ((board->flags & GO7007_USB_EZUSB) &&
1266: usbdev->speed != USB_SPEED_HIGH)
1267: dev_err(go->dev, "*** WARNING *** This device must be connected to a USB 2.0 port! Attempting to capture video through a USB 1.1 port will result in stream corruption, even at low bitrates!\n");
1268:
1269: /* Allocate the URBs and buffers for receiving the video stream */
1270: if (board->flags & GO7007_USB_EZUSB) {
1271: if (!usb->usbdev->ep_in[6])
1272: goto allocfail;
1273: v_urb_len = 1024;
1274: video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);
1275: } else {
1276: if (!usb->usbdev->ep_in[1])
1277: goto allocfail;
1278: v_urb_len = 512;
1279: video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
1280: }
1281: for (i = 0; i < 8; ++i) {
1282: usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
1283: if (usb->video_urbs[i] == NULL)
1284: goto allocfail;
1285: usb->video_urbs[i]->transfer_buffer =
1286: kmalloc(v_urb_len, GFP_KERNEL);
1287: if (usb->video_urbs[i]->transfer_buffer == NULL)
1288: goto allocfail;
1289: usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
1290: usb->video_urbs[i]->transfer_buffer, v_urb_len,
1291: go7007_usb_read_video_pipe_complete, go);
1292: }
1293:
1294: /* Allocate the URBs and buffers for receiving the audio stream */
1295: if ((board->flags & GO7007_USB_EZUSB) &&
1296: (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) {
1297: if (!usb->usbdev->ep_in[8])
1298: goto allocfail;
1299: for (i = 0; i < 8; ++i) {
]
|
| 217/2 |
2026/07/30 12:43 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 120336
output: 683
thoughts: 913
Thoughts: **Debugging a USB Connection with Syzkaller**
Okay, so I'm diving into this `go7007` issue and it looks like it's connected to `0x0eb1:0x7007`. The goal is to figure out how to use `syz_usb_connect` with custom `idVendor` and `idProduct` values. I already know that I can pass a `usb_device_descriptor` struct to achieve this.
The immediate problem is an error: `"wrong array arg *prog.BufferType"`. It seems I'm passing a buffer when an array is required. Let me check the definition of `usb_interface_descriptor` for clues.
```
usb_interface_descriptor {
inner usb_interface_descriptor_eps_array_t[int8, int8, const[0, int8], const[0, int8], const[0, int8], array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
} [packed]
```
Alright, the `inner` field uses `usb_interface_descriptor_eps_array_t`, which in turn contains a struct with 11 fields. Now, `extra` is an `array[usb_interface_extra_descriptor, 0:2]` and `endpoints` is `array[usb_endpoint_descriptor, 0:16]`. My initial instinct was that passing empty arrays `[]` for both `extra` and `endpoints` would satisfy the requirement.
But the error persists. Let me examine the problematic line of code within the `syz_usb_connect` call. The problematic segment seems to be the `interfaces` array. Now, the key is this - `interfaces` is `array[usb_interface_descriptor, 1:4]`. The error traces back to where I'm passing `[{{0, 0, 0, 0, 0, 3, 0, 0, 0, [], []}}]`.
Aha! `usb_interface_descriptor` is a struct, but with only one member called `inner`! So, the corrected format to pass should be `[{inner={0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}]`. Let's give that a shot and see if this solves the `wrong array arg` error.
|
| 218/2 |
2026/07/30 12:43 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={@inner={0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, 0, [@inner={0, 0, 0, 0, 0, 0, 0x80, 0, [@inner={0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}]}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 219/2 |
2026/07/30 12:43 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 122708
output: 678
thoughts: 203
Thoughts: **Debugging USB Device Descriptor Initialization**
Okay, so I was looking at this `usb_device_descriptor` and I jumped to a conclusion based on potentially incomplete information. I see it's *not* a union, but rather a struct. That's a fundamental misunderstanding on my part β this will impact how I should be looking at the structure. This changes how I interpret the memory layout and field access.
Therefore, the correct initialization should not be based on an assumption of a union structure. I need to make sure I am using the struct-specific initialization pattern and have the array type initialization correct. I am getting something of a default initialization of sorts: `&AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, 0, [{{0, 0, 0, 0, 0, 0, 0x80, 0, [{{0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}]}}]}}`. This is now my baseline to assess.
|
| 220/2 |
2026/07/30 12:43 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, 0, [{{0, 0, 0, 0, 0, 0, 0x80, 0, [{{0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 221/2 |
2026/07/30 12:43 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 124031
output: 679
thoughts: 1870
Thoughts: **Debugging a Syzkaller USB Descriptor**
Okay, let's break this down. I'm looking at the definition of `usb_config_descriptor` and I see it contains `usb_config_descriptor_ifaces_array_t`, which in turn contains `usb_config_descriptor_t`. Further down, I see `usb_config_descriptor_t` which is defined using `usb_config_descriptor_verbose_t`. Tracing it through, this ultimately means the Syzkaller description I have should be aligned with the fields within `usb_config_descriptor_verbose_t`.
I've got a struct literal, and I have to make sure the field count is accurate. Looking at `usb_config_descriptor_verbose_t`, I've identified the fields: `bLength`, `bDescriptorType`, `wTotalLength`, `bNumInterfaces`, `bConfigurationValue`, `iConfiguration`, `bmAttributes`, `bMaxPower`, `extra` and `interfaces`. However, I need to take into account that `extra` is `void`, which is omitted in the struct literal. So that means the `interfaces` field is the 9th, and *last* field, not the 8th. I see I've provided 9 fields in my input, but the format is throwing me off, specifically, `{{0, 0, 0, 0, 0, 0, 0x80, 0, [{{0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}]}}`.
I'm getting a "wrong array arg *prog.BufferType" error, so I need to go deeper. Let's look at `usb_interface_descriptor_verbose_t`. It also has `extra` and `endpoints` which are arrays. This gives me a hint, so I can try to understand `usb_interface_descriptor`. Now I am looking at `usb_interface_descriptor` itself. The definition tells me that is composed of a single field `inner` of type `usb_interface_descriptor_eps_array_t`.
`usb_interface_descriptor_eps_array_t` then expands to `usb_interface_descriptor_t`, ultimately linking back to `usb_interface_descriptor_verbose_t` which defines the fields within the `usb_interface_descriptor`. Looking closer, the fields are: `bLength`, `bDescriptorType`, `bInterfaceNumber`, `bAlternateSetting`, `bNumEndpoints`, `bInterfaceClass`, `bInterfaceSubClass`, `bInterfaceProtocol`, `iInterface`, `extra`, and `endpoints`. So, that struct also has 11 fields. Now, I see the light, `usb_config_descriptor` has an array of `usb_interface_descriptor`.
So, the problem is with the way I'm defining the `interfaces` array within the `usb_config_descriptor`. Because `usb_interface_descriptor` contains an inner struct, and that has 11 fields, my literal should be an array of structs where each item is also a nested struct. The error message is correct, the compiler expects a struct, or rather the nested structure within, as the `interfaces` contains the `usb_interface_descriptor` data. The literal needs to be structured properly to reflect this nesting.
I'm going to correct the array of `usb_interface_descriptor` entries, so that each item is structured as a nested struct: `[{{{0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}}]`.
|
| 222/2 |
2026/07/30 12:44 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, 0, [{{0, 0, 0, 0, 0, 0, 0x80, 0, [{{{0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 223/2 |
2026/07/30 12:44 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 127548
output: 680
thoughts: 623
Thoughts: **Debugging a USB Configuration Descriptor**
Okay, let's break this down. It looks like I'm wrestling with how `usb_config_descriptor` is being represented and initialized. I'm seeing that `usb_config_descriptor` is a struct, and I'm pretty sure it's got a single field called `inner`, which itself seems to be a struct containing 9 fields. My initial thought was that a complete initialization would look something like `{{0, 0, 0, 0, 0, 0, 0x80, 0, [...]}}`.
I'm using `configs` as an array of `usb_config_descriptor`, and `interfaces` as an array of `usb_interface_descriptor`, so I was expecting this nested structure, with `interfaces` having a specific format: `[{{{0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}}]`. But I'm getting an error, and the error points to the `interfaces` array.
Now I'm looking closely at the descriptor structure. There's a `usb_config_descriptor_t` and it has a field called `EXTRA` that is defined as `void`. I know `void` means a type with static size zero, and usually it's used within templates or varlen unions. But I'm unsure if it plays a part in the struct literal. Does a struct in syzkaller include a `void` field? Will it appear as `{}` or simply be omitted?
The critical part is the ordering. If `void` is omitted, the `interfaces` field is the ninth field. If `void` is *not* omitted, it takes up the ninth position, and the `interfaces` array is the tenth.
So, I'm going to test the hypothesis that providing `{}` for `extra` will solve the problem. Let's see if this revised literal, `[{{0, 0, 0, 0, 0, 0, 0x80, 0, {}, [{{{0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}}]}}]`, does the trick.
|
| 224/2 |
2026/07/30 12:44 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, 0, [{{0, 0, 0, 0, 0, 0, 0x80, 0, {}, [{{{0, 0, 0, 0, 0, 0, 0, 0, 0, [], []}}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 225/2 |
2026/07/30 12:44 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 129518
output: 666
thoughts: 1817
Thoughts: **Debugging Syzkaller Struct Literals for USB Descriptors**
Okay, so I'm seeing this "wrong struct arg for void" error, and it's throwing me for a loop. Clearly, `void` doesn't take `{}`. The question then becomes, what does `void` actually *do*? I suspect it's omitted entirely. But if that's the case, then fields in my struct are going to be misaligned. In this instance, the `interfaces` field is coming in as field nine. I tried to provide an argument for the field, but it was incorrect. The problem has to do with understanding how `len` and `const` fields work in syzkaller.
Let me break this down using the `usb_config_descriptor` and the other associated structs. Looking at `usb_config_descriptor`, there is a nested structure `usb_config_descriptor_verbose_t`. Inside that structure, `bNumInterfaces` is defined as `IFSNUM`, which is `len[interfaces, int8]`. It now makes sense! `bNumInterfaces` is a `len` field, so it is automatically computed and omitted from the struct literal, which means I should not provide an argument for it. Similarly, `wTotalLength` is another `len` field, and it also is omitted. Now I understand!
I need to figure out which fields in the structure take values and which are omitted. I know that `const` fields *do* take values.
Looking at `usb_config_descriptor_verbose_t`, the fields that take a value are: `bLength`, `bDescriptorType`, `bConfigurationValue`, `iConfiguration`, `bmAttributes`, `bMaxPower`, and `interfaces`. That's seven fields. Now let's look at `usb_device_descriptor_verbose_t`: this one has `bNumConfigurations`, which is `len`, so it is omitted. This structure has fourteen fields. Finally, I will look at `usb_interface_descriptor_verbose_t`: Here, `bNumEndpoints` is also a `len` field that will be omitted. The fields that take a value are: `bLength`, `bDescriptorType`, `bInterfaceNumber`, `bAlternateSetting`, `bInterfaceClass`, `bInterfaceSubClass`, `bInterfaceProtocol`, `iInterface`, `extra`, and `endpoints`. So, 10 fields!
With a better understanding of what fields are included and omitted, let me construct the struct literals!
* `usb_device_descriptor`: I'm thinking this one will be `{{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, [CONFIG]}}` which gives me 14 fields.
* `CONFIG`: `{{0, 0, 0, 0, 0x80, 0, [INTERFACE]}}` - a total of 7 fields.
* `INTERFACE`: I should have this as `{{0, 0, 0, 0, 3, 0, 0, 0, [], []}}` which will yield 10 fields.
Okay, let's give it a try and see if I've finally cracked this!
|
| 226/2 |
2026/07/30 12:45 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, [{{0, 0, 0, 0, 0x80, 0, [{{0, 0, 0, 0, 3, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 227/2 |
2026/07/30 12:45 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 132894
output: 674
thoughts: 1193
Thoughts: **Debugging a Syzkaller Descriptor**
Okay, first things first, that "wrong array arg" error is throwing me off. Ah, right, `bNumConfigurations` is a `len` field, determined by the size of the `configs` array. Now, I have to remember, Syzkaller *doesn't* omit `len` fields in its syntax, they're represented as `AUTO`!
Right, I've used `AUTO` before, but got a "wrong type" error. This means `AUTO` isn't compatible with `IntType`. But, if `len` fields are of `LenType`, maybe `AUTO` works for *that*! Let's check my previous attempt: the problem was definitely with `AUTO`, so I'll try to understand where it was going wrong.
The error message pointed out that I used `AUTO` with `IntType`. So, which field was an `IntType`? `bLength`, `bDescriptorType`, `bDeviceClass`, `bDeviceSubClass`, `bDeviceProtocol`, `bcdDevice`, `iManufacturer`, `iProduct`, and `iSerialNumber` are all `const` fields and, therefore, of `ConstType`.
So, does `AUTO` work for `ConstType`? Wait, I think I tried `0` for `ConstType` before, and that worked!
Okay, let's break down the structure of `usb_device_descriptor_verbose_t`. I'll go through the fields one by one:
1. `bLength` (ConstType) - `0`
2. `bDescriptorType` (ConstType) - `0`
3. `bcdUSB` (FlagsType) - `0x200`
4. `bDeviceClass` (ConstType) - `0`
5. `bDeviceSubClass` (ConstType) - `0`
6. `bDeviceProtocol` (ConstType) - `0`
7. `bMaxPacketSize0` (FlagsType) - `64`
8. `idVendor` (ConstType) - `0x10c4`
9. `idProduct` (ConstType) - `0x8244`
10. `bcdDevice` (ConstType) - `0`
11. `iManufacturer` (ConstType) - `0`
12. `iProduct` (ConstType) - `0`
13. `iSerialNumber` (ConstType) - `0`
14. `bNumConfigurations` (LenType) - `AUTO`
15. `configs` (ArrayType) - `[CONFIG]`
Now, each `CONFIG` is:
1. `bLength` (ConstType) - `0`
2. `bDescriptorType` (ConstType) - `0`
3. `wTotalLength` (LenType) - `AUTO`
4. `bNumInterfaces` (LenType) - `AUTO`
5. `bConfigurationValue` (IntType) - `0`
6. `iConfiguration` (IntType) - `0`
7. `bmAttributes` (FlagsType) - `0x80`
8. `bMaxPower` (IntType) - `0`
9. `extra` (VoidType) - Omitted!
10. `interfaces` (ArrayType) - `[INTERFACE]`
So, `extra` is `void`, that's what makes it omitted. I'll remember this, so that's nine fields for the `CONFIG` struct.
Finally, `INTERFACE` looks like:
1. `bLength` (ConstType) - `0`
2. `bDescriptorType` (ConstType) - `0`
3. `bInterfaceNumber` (IntType) - `0`
4. `bAlternateSetting` (IntType) - `0`
5. `bNumEndpoints` (LenType) - `AUTO`
6. `bInterfaceClass` (ConstType) - `3`
7. `bInterfaceSubClass` (ConstType) - `0`
8. `bInterfaceProtocol` (ConstType) - `0`
9. `iInterface` (IntType) - `0`
10. `extra` (ArrayType) - `[]`
11. `endpoints` (ArrayType) - `[]`
Alright, let's give this a shot!
|
| 228/2 |
2026/07/30 12:45 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, [{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 229/2 |
2026/07/30 12:45 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 135937
output: 675
thoughts: 115
Thoughts: **Decoding this USB Descriptor Structure**
Okay, so I'm looking at this `interfaces` field, and it's defined as an `array[usb_interface_descriptor, 1:4]`. Right, so it's an array of USB interface descriptors, up to four of them. Now, the crucial part is that `usb_interface_descriptor` itself is defined as a struct, but with only *one* field, which is `inner`. Therefore, when I try to parse this data, it should look something like this: `[{inner={0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]`. My immediate thought is, let me try and apply this nested structure explicitly. So, given that `inner` is the sole member of `usb_interface_descriptor`, I believe the correct form to try is `[{{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}]`. That should give me the correct interpretation.
|
| 230/2 |
2026/07/30 12:45 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, [{{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 231/2 |
2026/07/30 12:45 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 137129
output: 674
thoughts: 1214
Thoughts: **Deconstructing the USB Configuration Descriptor**
Okay, let's break this down systematically. I'm focusing on constructing the `usb_config_descriptor` structure. First, the definition: `usb_config_descriptor` has one field, `inner`. Therefore, when I'm looking at the `CONFIG` part, it should translate to something like `{{...}}`. Specifically, `CONFIG` represents `{inner={...}}`.
Now, digging into the `usb_config_descriptor_ifaces_array_t` type, it seems to be built on top of `usb_config_descriptor_t`, which in turn depends on `usb_config_descriptor_verbose_t`. Looking at `usb_config_descriptor_verbose_t`, I see that it includes an `extra` field, which can be `void`, meaning it's potentially omitted. This is the key. If `extra` is omitted, then the `interfaces` field *becomes* the 9th field in the structure, not the 10th. This is critical.
So, `usb_config_descriptor_verbose_t` has 10 fields (or 9 if `extra` is omitted), so the ninth element will be the `interfaces` array.
Now let's consider the device descriptor, and the `configs` field. `usb_device_descriptor_verbose_t` has a `configs` field, and `configs` is an array of `usb_config_descriptor`. Since a `usb_config_descriptor` is `{inner}`, the `configs` should be `[{inner}]`. This means `configs` will be an array of `usb_config_descriptor`. Thus, `configs` should be `[{{...}}]`.
The `inner` of `usb_config_descriptor` contains all the elements: `bLength, bDescriptorType, wTotalLength, bNumInterfaces, bConfigurationValue, iConfiguration, bmAttributes, bMaxPower, interfaces`. So `configs` should be something like `[{{bLength, ...}}]`.
The `interfaces` is an array of `usb_interface_descriptor`s. And each `usb_interface_descriptor` contains an `inner` field. Therefore, this means `interfaces` becomes `[{inner}]`. Where `inner` represents `bLength, bDescriptorType, bInterfaceNumber, bAlternateSetting, bNumEndpoints, bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, iInterface, extra, endpoints`. So `interfaces` is `[{{bLength, ...}}]`.
Let's double-check the brace counts and structure again: `configs = [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, [{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]}}]`. Now that I've reviewed the structural components and the relationship between each element of this configuration, I'm ready to write that structure exactly.
|
| 232/2 |
2026/07/30 12:45 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, [{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 233/2 |
2026/07/30 12:45 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 139844
output: 666
thoughts: 1656
Thoughts: **Debugging USB Descriptor Structures**
Okay, here's the breakdown of my thought process. I'm hitting a "wrong array arg" error when dealing with USB descriptors, specifically related to the `interfaces` field. The error suggests it's expecting a byte array (`BufferType`), but I'm giving it an array of structs. That's the core issue.
First, I need to understand what `interfaces` *actually* is within the structure. I know `usb_config_descriptor_verbose_t` uses `IFS` for `interfaces`, so let's trace that. Looking at the definition, `IFS` resolves to `array[usb_interface_descriptor, 1:4]`, which is, indeed, an array of `usb_interface_descriptor` structs. So, the original error is misleading.
The problem likely lies elsewhere. Let's consider that the `extra` field, which I thought was omitted, might not be. If not omitted it is parsed as `extra` or parsed as `void`. The struct definition in `usb_config_descriptor` has an `extra` field that's `void`. If not omitted, `extra` doesn't take up any fields, so there's really no effect.
I need to confirm the field order and what's omitted by syzkaller. I need to count the fields in `usb_config_descriptor_verbose_t`. Counting each field, taking into account which ones are `len` fields (omitted in syzkaller), shows that there are only 7 fields that should be populated: `bLength`, `bDescriptorType`, `bConfigurationValue`, `iConfiguration`, `bmAttributes`, `bMaxPower`, and `interfaces`.
Looking back at my code, I was providing 9 fields when the length field was being omitted, because I used `AUTO` to define the `len` fields. I have to remove the `AUTO` entries for those omitted length fields, and my values should be: `{{0, 0, 0, 0, 0x80, 0, [{{...}}]}}`.
Now, let's make sure I didn't make the same mistake elsewhere. I need to make sure `usb_device_descriptor_verbose_t` also doesn't contain the mistake I just caught in `usb_config_descriptor_verbose_t`. Counting all the fields and omitting the fields that are of `len` type confirms I only need to supply 14 fields, and I had 15, because I set `AUTO` on the length field, so that needs to be removed.
Finally, I need to check `usb_interface_descriptor_verbose_t` to be sure I am correct, which contains 10 fields and I have 11 fields because of another `AUTO` length field, so I should be at `{{0, 0, 0, 0, 3, 0, 0, 0, [], []}}`.
With the corrected number of fields in each descriptor, the structs should now be defined as follows: `INTERFACE` is `{{0, 0, 0, 0, 3, 0, 0, 0, [], []}}`, `CONFIG` is `{{0, 0, 0, 0, 0x80, 0, [INTERFACE]}}`, and `DEVICE` is `{{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, [CONFIG]}}`. Let's give this a try and see if it works.
|
| 234/2 |
2026/07/30 12:46 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, [{{0, 0, 0, 0, 0x80, 0, [{{0, 0, 0, 0, 3, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 235/2 |
2026/07/30 12:46 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 143129
output: 674
thoughts: 983
Thoughts: **Debugging USB Descriptor Generation**
Okay, hold on. That initial error, `wrong array arg *prog.LenType`, immediately points to a problem with field 14 β which is actually a `LenType`. Aha! This means `bNumConfigurations` isn't omitted! I was wrong to assume that. If it's *not* omitted, I *must* provide `AUTO` for it. But wait... when I *did* provide `AUTO` earlier, the error was "wrong type *prog.IntType for AUTO"! I need to re-examine that specific error message.
Okay, let's look at the failing line: `r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, 0, [{{0, 0, 0, 0, 0, 0, 0x80, 0, [<<<!!ERROR!!>>>]}}]}}, 0)`. The error isn't at the `AUTO` *itself* but in the array. It's actually: `wrong type *prog.IntType for AUTO` at the nested array part of `bConfigurationValue`! I was accidentally inputting the wrong type for *that* field and the debugger was complaining about it!
Let me check again: the error is at `&AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, [{{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}]}}]}}`. Now I see it. The error is `wrong array arg *prog.BufferType` within the innermost structure: `{{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}`.
I need to map this back to the correct fields. If the `len` fields are *not* omitted, then the `usb_device_descriptor_verbose_t` has 15 fields. `usb_config_descriptor_verbose_t` has 10 fields (assuming `extra` is omitted), and `usb_interface_descriptor_verbose_t` has 11 fields. Now, I have a clear plan. I'll provide `AUTO` for all `len` fields, and `0` for all `const` and `int` fields:
For the `DEVICE` descriptor:
* `bLength = 0`
* `bDescriptorType = 0`
* `bcdUSB = 0x200`
* `bDeviceClass = 0`
* `bDeviceSubClass = 0`
* `bDeviceProtocol = 0`
* `bMaxPacketSize0 = 64`
* `idVendor = 0x10c4`
* `idProduct = 0x8244`
* `bcdDevice = 0`
* `iManufacturer = 0`
* `iProduct = 0`
* `iSerialNumber = 0`
* `bNumConfigurations = AUTO`
* `configs = [CONFIG]`
For the `CONFIG` descriptor:
* `bLength = 0`
* `bDescriptorType = 0`
* `wTotalLength = AUTO`
* `bNumInterfaces = AUTO`
* `bConfigurationValue = 0`
* `iConfiguration = 0`
* `bmAttributes = 0x80`
* `bMaxPower = 0`
* `interfaces = [INTERFACE]` (with the assumption `extra` is omitted)
For the `INTERFACE` descriptor:
* `bLength = 0`
* `bDescriptorType = 0`
* `bInterfaceNumber = 0`
* `bAlternateSetting = 0`
* `bNumEndpoints = AUTO`
* `bInterfaceClass = 3`
* `bInterfaceSubClass = 0`
* `bInterfaceProtocol = 0`
* `iInterface = 0
|
| 236/2 |
2026/07/30 12:46 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, [{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 237/2 |
2026/07/30 12:46 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 145981
output: 675
thoughts: 578
Thoughts: **Debugging a `BufferType` Mismatch**
Okay, so I'm getting a "wrong array arg" error related to `prog.BufferType` at this specific array: `[{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]`. My initial thought is that the code expects a `BufferType` for the `interfaces` argument. But wait, `interfaces` is actually of type `IFS`, not a direct `BufferType`. What *is* `IFS`? Let's trace this.
`usb_config_descriptor_t` uses `usb_config_descriptor_verbose_t`, which in turn involves `IFS`. Okay. Then `usb_config_descriptor` itself employs `usb_config_descriptor_ifaces_array_t`. That holds an array of `usb_interface_descriptor` instances, with size 1 to 4. Therefore, `IFS` *is* this array of `usb_interface_descriptor`s. And looking at the definition of `usb_interface_descriptor`, it's a struct with only one field, called `inner`.
So, `INTERFACE` should be `{inner={...}}`. And based on the provided array, `[INTERFACE]` should indeed look like `[{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]`. Hang on a second... I *did* provide that! That's the array I'm passing!
Aha! Now I see. The problem is that the given array `{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}` actually contains 11 fields, but the `usb_interface_descriptor` structure has only a single field named `inner`. The provided array, as a whole, is a representation of the *inner* field, of the `usb_interface_descriptor` structure. Therefore, the format I've provided is incorrect. It should be a single structure, with a single member that looks like the given array: `{{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}`. It's a structure with a structure containing the 11-field array.
Let me try that and see if it fixes the problem.
|
| 238/2 |
2026/07/30 12:46 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, [{{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 239/2 |
2026/07/30 12:46 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 147927
output: 667
thoughts: 1072
Thoughts: **Debugging USB Descriptor Structures**
Okay, here's what's running through my mind as I troubleshoot this descriptor parsing issue. I've encountered this error again using `[{{{...}}}]` -- darn! I need to dig deeper. I need to understand why my descriptor structures aren't being interpreted correctly.
First, let me re-examine `usb_config_descriptor_verbose_t`. I'm going through the field definitions:
```c
type usb_config_descriptor_verbose_t[NUM, IFSNUM, ICONFIG, ATTRS, POWER, EXTRA, IFS] {
bLength const[USB_DT_CONFIG_SIZE, int8]
bDescriptorType const[USB_DT_CONFIG, int8]
wTotalLength len[parent, int16]
bNumInterfaces IFSNUM
bConfigurationValue NUM
iConfiguration ICONFIG
bmAttributes ATTRS
bMaxPower POWER
extra EXTRA
interfaces IFS
} [packed]
```
Alright, `EXTRA` being `void` means it is omitted, so the key takeaway is that the `interfaces` field is the 9th field. However, `wTotalLength` is a `len` field, so it is omitted from the input structure. Similarly, `bNumInterfaces` is also a `len` field and is omitted.
This means the actual fields are:
1. `bLength`
2. `bDescriptorType`
3. `bConfigurationValue`
4. `iConfiguration`
5. `bmAttributes`
6. `bMaxPower`
7. `interfaces`
I had counted 7 fields! But I provided 9 fields: `0, 0, AUTO, AUTO, 0, 0, 0x80, 0, [INTERFACE]`. The `AUTO` fields are the problem. They correspond to the omitted `wTotalLength` and `bNumInterfaces`. I need to remove those `AUTO` values! So the correct format for the CONFIG descriptor should be `{{0, 0, 0, 0, 0x80, 0, [INTERFACE]}}`.
Now, let's double-check the `usb_device_descriptor_verbose_t` structure. Looking at the fields:
1. `bLength`
2. `bDescriptorType`
3. `bcdUSB`
4. `bDeviceClass`
5. `bDeviceSubClass`
6. `bDeviceProtocol`
7. `bMaxPacketSize0`
8. `idVendor`
9. `idProduct`
10. `bcdDevice`
11. `iManufacturer`
12. `iProduct`
13. `iSerialNumber`
14. `configs`
Ah, `bNumConfigurations` is again a `len` field and omitted. So there are indeed 14 fields. I provided 15 fields, with `AUTO` for `bNumConfigurations`, so I need to remove that `AUTO` field.
Finally, `usb_interface_descriptor_verbose_t`:
1. `bLength`
2. `bDescriptorType`
3. `bInterfaceNumber`
4. `bAlternateSetting`
5. `bInterfaceClass`
6. `bInterfaceSubClass`
7. `bInterfaceProtocol`
8. `iInterface`
9. `extra`
10. `endpoints`
This has 10 fields and I incorrectly provided 11 fields. `bNumEndpoints` is a `len` field and is omitted as well. So, I must remove the `AUTO` value for it too.
Okay, let's assemble the correct descriptor strings based on this.
* `DEVICE`: `{{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, [CONFIG]}}` (14 fields)
* `CONFIG`: `{{0, 0, 0, 0, 0x80, 0, [INTERFACE]}}` (7 fields)
* `INTERFACE`: `{{{0, 0, 0, 0, 3, 0, 0, 0, [], []}}}` (10 fields inside `inner`)
I'm confident this is correct. I will try this!
|
| 240/2 |
2026/07/30 12:47 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, [{{0, 0, 0, 0, 0x80, 0, [{{{0, 0, 0, 0, 3, 0, 0, 0, [], []}}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 241/2 |
2026/07/30 12:47 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 150844
output: 674
thoughts: 1565
Thoughts: **Debugging USB Configuration Descriptor Handling**
Okay, first things first, I see this "wrong array arg *prog.LenType" error. That means the `LenType` field is definitely present. So, the `len` fields are *not* omitted, which means I *must* supply a value for them. But when I tried `AUTO`, it complained about the wrong type.
Let's revisit the error when I used `AUTO` for `bNumConfigurations`. The error specifically pinpoints the issue here: `[{{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}]`. Interestingly, `AUTO` for `bNumConfigurations` *did* work. The error is located within this nested structure. The key is that `AUTO` seems fine for the configuration count itself.
Why is it complaining about `*prog.BufferType`? Because `interfaces` is the 9th field, after `extra`. Now, if `extra` is `void`, does it even take a field? If it does not, `interfaces` *is* the 9th field. I provided a value for `interfaces` in my initial input. My input looked like this: `[{{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}]`. But, the error persists!
Could it be that the `void` for `extra` means the field is omitted, and that the `interfaces` field is, in fact, not a `BufferType`? But, if `EXTRA` is `void`, it might mean `BufferType` is expected. No, void is static size 0.
Let's look at `usb_config_descriptor_verbose_t` again. If `extra` is `void`, then the type is omitted. So `IFS` is `array[usb_interface_descriptor, 1:4]`. The problem is that the tool reports a *BufferType* mismatch for the array. Okay, let's step back and look at the types again: the `usb_config_descriptor` has `inner usb_config_descriptor_ifaces_array_t`. `usb_config_descriptor_ifaces_array_t` then contains `usb_interface_descriptor`.
Now I need to understand what `usb_interface_descriptor` actually *is*. Aha! It's a structure with a single field called `inner`. Okay, so `usb_interface_descriptor` is `{inner}`. This means the array is `[{inner}]`. Since `inner` is a struct, its members include `bLength`. Therefore, the array is `[{{bLength, ...}}]`.
Let's count again. It seems I provided `[{{{bLength, ...}}}]`. That's one set of extra braces! In syzkaller, array of structs is declared like this: `[{field1, field2}, {field1, field2}]`. So my array should have been `[{{inner}}]`. The inner has members such as `bLength`. Therefore `interfaces` should be `[{{bLength, ...}}]`. I mistakenly added one set of extra braces! Let's try removing them!
|
| 242/2 |
2026/07/30 12:47 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, [{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
|
| 243/2 |
2026/07/30 12:47 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 153917
output: 675
thoughts: 784
Thoughts: **Debugging a Structure Parsing Error**
Okay, so I got this `wrong array arg *prog.BufferType` error, and my initial thought was that the issue was with how I was handling the `interfaces` array, which I'm defining as `[{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]`. But I need to think this through a bit more methodically. If that array is causing a `BufferType` error, then clearly `interfaces` isn't a simple array of structs like I initially assumed.
I need to reconsider the role of `extra` here. If `extra` isn't omitted, then it occupies the 9th field, and `interfaces` is the 10th. And `extra` is defined as `void`. But a `void` doesn't take a value, so what's going on here? If I feed in the array where I expect the `void` to be, it's attempting to parse that array as the `void` field, and it's choking on it since `void` is a type with a static size of 0.
Let's look more closely at the struct definitions. Ah, `usb_config_descriptor_verbose_t` has `interfaces` defined as `IFS`, and let's go with the assumption that `IFS` is `BufferType`. What is `usb_config_descriptor_ifaces_array_t`?
```
usb_config_descriptor_ifaces_array_t[NUM, IFS] usb_config_descriptor_t[NUM, len[interfaces, int8], IFS]
```
and `usb_config_descriptor` is:
```
inner usb_config_descriptor_ifaces_array_t[int8, array[usb_interface_descriptor, 1:4]]
```
So it looks like `IFS` is `array[usb_interface_descriptor, 1:4]`. Okay, so `interfaces` is an array of `usb_interface_descriptor`. But that shouldn't cause this error.
Now, wait a minute! Could this `wrong array arg *prog.BufferType` *not* be about `interfaces` at all? Is it about `configs` in `usb_device_descriptor_verbose_t`? No, the error clearly points to the problematic `interfaces` data. Okay, back on track, then.
Perhaps if `extra` is `void` and it IS somehow parsed as `BufferType`. No, `void` is `void`. That doesn't make any sense.
Let me go back and re-check `usb_config_descriptor_t`:
```
usb_config_descriptor_t[NUM, IFSNUM, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, void, IFS]
```
Yes, `EXTRA` is indeed `void`. So, if `void` might be represented as `""` (empty string). Let's try `"", [{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]`! That might just work.
|
| 244/2 |
2026/07/30 12:47 |
tool |
reproduce-crash |
2m
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, "", [{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID:repro/67137852399770c652e691f9d4806cf4f88259e0 ReproducedBugTitle: ReproducedCrashReport:]
|
| 245/2 |
2026/07/30 12:49 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 156165
output: 61
thoughts: 34
Thoughts: **A Moment of Triumph and Quick Assessment**
Yes! Finally, that worked! I knew `""` was the correct string representation for `void` in this context. It's satisfying to see it click after all the testing.
Hmm, but wait... it didn't crash, which is good, but it's not the primary goal. I suppose that's a positive, but I'm more interested in seeing a clear indication that it's doing the right thing.
Right, time to check the coverage and verify that the test case is firing as I'd expect. Make sure the logic is getting exercised properly by this fix. A successful outcome will need to be verified.
|
| 246/2 |
2026/07/30 12:50 |
tool |
get-coverage-files |
0m
Args: map[ExecutionCachedID:repro/67137852399770c652e691f9d4806cf4f88259e0]
Results: map[Files:[arch/x86/entry/vsyscall/vsyscall_64.c arch/x86/include/asm/atomic64_64.h arch/x86/include/asm/bitops.h arch/x86/include/asm/compat.h arch/x86/include/asm/cpufeature.h arch/x86/include/asm/irqflags.h arch/x86/include/asm/jump_label.h arch/x86/include/asm/mmu_context.h arch/x86/include/asm/page.h arch/x86/include/asm/pgtable.h arch/x86/include/asm/pkru.h arch/x86/include/asm/preempt.h arch/x86/include/asm/trace/fpu.h arch/x86/kernel/cpu/aperfmperf.c arch/x86/kernel/fpu/context.h arch/x86/kernel/fpu/core.c arch/x86/kernel/fpu/internal.h arch/x86/kernel/fpu/xstate.c arch/x86/kernel/tsc.c arch/x86/mm/fault.c arch/x86/mm/maccess.c arch/x86/mm/pgtable.c arch/x86/pci/common.c arch/x86/pci/direct.c block/blk-cgroup.c drivers/acpi/acpica/nsaccess.c drivers/acpi/acpica/nsdump.c drivers/acpi/acpica/nssearch.c drivers/acpi/acpica/nsutils.c drivers/acpi/acpica/nsxfname.c drivers/acpi/acpica/utascii.c drivers/acpi/acpica/utdebug.c drivers/acpi/acpica/utmutex.c drivers/acpi/acpica/utstring.c drivers/acpi/device_pm.c drivers/acpi/osl.c drivers/acpi/property.c drivers/acpi/utils.c drivers/base/core.c drivers/base/map.c drivers/base/power/qos.c drivers/base/power/runtime.c drivers/base/power/wakeirq.c drivers/char/misc.c drivers/i2c/busses/i2c-i801.c drivers/i2c/i2c-core-base.c drivers/i2c/i2c-core-smbus.c drivers/i2c/i2c-core.h drivers/i2c/i2c-dev.c drivers/media/common/videobuf2/videobuf2-core.c drivers/media/common/videobuf2/videobuf2-v4l2.c drivers/media/mc/mc-request.c drivers/media/test-drivers/vicodec/codec-v4l2-fwht.c drivers/media/test-drivers/vicodec/vicodec-core.c drivers/media/v4l2-core/v4l2-ctrls-core.c drivers/media/v4l2-core/v4l2-ctrls-defs.c drivers/media/v4l2-core/v4l2-ctrls-request.c drivers/media/v4l2-core/v4l2-dev.c drivers/media/v4l2-core/v4l2-fh.c drivers/media/v4l2-core/v4l2-mem2mem.c drivers/pci/access.c drivers/pci/ats.c drivers/pci/host-bridge.c drivers/pci/iov.c drivers/pci/msi/api.c drivers/pci/msi/msi.c drivers/pci/pci-acpi.c drivers/pci/pci-driver.c drivers/pci/pci.c drivers/pci/pcie/aer.c drivers/pci/pcie/aspm.c drivers/pci/quirks.c drivers/pci/rebar.c drivers/pci/vc.c drivers/usb/gadget/legacy/raw_gadget.c fs/char_dev.c fs/d_path.c fs/dcache.c fs/file.c fs/file_table.c fs/ioctl.c fs/libfs.c fs/mnt_idmapping.c fs/namei.c fs/namespace.c fs/notify/fsnotify.c fs/open.c include/acpi/acpi_bus.h include/asm-generic/bitops/instrumented-non-atomic.h include/asm-generic/pgalloc.h include/linux/atomic/atomic-arch-fallback.h include/linux/atomic/atomic-instrumented.h include/linux/atomic/atomic-long.h include/linux/audit.h include/linux/bit_spinlock.h include/linux/cgroup.h include/linux/clockchips.h include/linux/cpumask.h include/linux/cred.h include/linux/dcache.h include/linux/delayed_call.h include/linux/device.h include/linux/device_cgroup.h include/linux/err.h include/linux/file.h include/linux/file_ref.h include/linux/filelock.h include/linux/find.h include/linux/folio_batch.h include/linux/fortify-string.h include/linux/fs.h include/linux/fs/super.h include/linux/fsnotify.h include/linux/fsnotify_backend.h include/linux/hrtimer.h include/linux/instrumented.h include/linux/jiffies.h include/linux/jump_label.h include/linux/kernel.h include/linux/kref.h include/linux/list.h include/linux/list_bl.h include/linux/llist.h include/linux/log2.h include/linux/lsm_hook_defs.h include/linux/maple_tree.h include/linux/memcontrol.h include/linux/mempolicy.h include/linux/mm.h include/linux/mmzone.h include/linux/mount.h include/linux/nodemask.h include/linux/page-flags.h include/linux/page_ext.h include/linux/page_ref.h include/linux/pagemap.h include/linux/perf_event.h include/linux/pgtable.h include/linux/pid.h include/linux/pm_qos.h include/linux/preempt.h include/linux/rbtree.h include/linux/rbtree_latch.h include/linux/rculist_bl.h include/linux/rcupdate.h include/linux/refcount.h include/linux/rmap.h include/linux/rtmutex.h include/linux/sched.h include/linux/sched/isolation.h include/linux/seqlock.h include/linux/spinlock_rt.h include/linux/srcu.h include/linux/swap.h include/linux/thread_info.h include/linux/uaccess.h include/linux/ucopysize.h include/linux/userfaultfd_k.h include/linux/vmstat.h include/linux/workqueue.h include/linux/xarray.h include/trace/events/exceptions.h include/trace/events/filemap.h include/trace/events/kmem.h include/trace/events/rpm.h include/trace/events/smbus.h include/trace/events/timer.h kernel/bpf/core.c kernel/cgroup/rstat.c kernel/kthread.c kernel/pid.c kernel/printk/printk_safe.c kernel/time/clockevents.c kernel/time/hrtimer.c kernel/time/posix-timers.c kernel/time/tick-oneshot.c kernel/time/tick-sched.c kernel/time/time.c kernel/time/timekeeping.c lib/errseq.c lib/idr.c lib/iomap.c lib/kobject.c lib/lockref.c lib/maple_tree.c lib/percpu_counter.c lib/plist.c lib/radix-tree.c lib/strncpy_from_user.c lib/timerqueue.c lib/usercopy.c lib/vsprintf.c lib/xarray.c mm/backing-dev.c mm/fail_page_alloc.c mm/filemap.c mm/internal.h mm/list_lru.c mm/maccess.c mm/memory.c mm/mempolicy.c mm/mmap_lock.c mm/page_counter.c mm/page_ext.c mm/page_owner.c mm/page_table_check.c mm/pgtable-generic.c mm/readahead.c mm/rmap.c mm/swap.c mm/swapfile.c security/device_cgroup.c security/integrity/ima/ima_main.c security/landlock/cred.h security/landlock/fs.c security/landlock/ruleset.c security/security.c security/smack/smack_access.c security/smack/smack_lsm.c security/tomoyo/audit.c security/tomoyo/common.c security/tomoyo/common.h security/tomoyo/domain.c security/tomoyo/file.c security/tomoyo/realpath.c security/tomoyo/tomoyo.c security/tomoyo/util.c usercopy_64.c]]
|
| 247/2 |
2026/07/30 12:50 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 159324
output: 52
thoughts: 220
Thoughts: **Debugging a USB Gadget Driver Issue**
Okay, so I'm looking at the USB gadget code, specifically `drivers/usb/gadget/legacy/raw_gadget.c`, but something's off. I'm not seeing any trace of the `si4713` radio driver in the coverage. Why not? Well, it hits me β the `si4713` driver is, after all, a radio driver, and there's no guarantee it will even be loaded, or that it'll correctly bind to `0x10c4:0x8244` unless the device descriptor matches up perfectly. It's a classic bind issue.
Then I remember something important: the `si4713` driver expects the interface class to be `USB_CLASS_HID`, which is class 3. I did, in fact, provide `bInterfaceClass = 3`. Good. But wait⦠what about the `bDeviceClass`? Ah, I set it to `0`. And `bNumEndpoints`, I also set that to `0`. That might be a problem.
That's when it hits me: the `si4713` driver has an interrupt endpoint! If `bNumEndpoints` is set to `0`, the driver is probably rejecting it outright. That makes sense; it likely expects at least one endpoint to be defined. I'd better confirm this, let's go check the probe function in `drivers/media/radio/si4713/radio-usb-si4713.c`.
|
| 248/2 |
2026/07/30 12:50 |
tool |
read-file |
0m
Args: map[File:drivers/media/radio/si4713/radio-usb-si4713.c FirstLine:100 LineCount:100]
Results: map[Contents: 100: static int vidioc_g_frequency(struct file *file, void *priv,
101: struct v4l2_frequency *vf)
102: {
103: struct si4713_usb_device *radio = video_drvdata(file);
104:
105: return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_frequency, vf);
106: }
107:
108: static const struct v4l2_ioctl_ops usb_si4713_ioctl_ops = {
109: .vidioc_querycap = vidioc_querycap,
110: .vidioc_g_modulator = vidioc_g_modulator,
111: .vidioc_s_modulator = vidioc_s_modulator,
112: .vidioc_g_frequency = vidioc_g_frequency,
113: .vidioc_s_frequency = vidioc_s_frequency,
114: .vidioc_log_status = v4l2_ctrl_log_status,
115: .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
116: .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
117: };
118:
119: /* File system interface */
120: static const struct v4l2_file_operations usb_si4713_fops = {
121: .owner = THIS_MODULE,
122: .open = v4l2_fh_open,
123: .release = v4l2_fh_release,
124: .poll = v4l2_ctrl_poll,
125: .unlocked_ioctl = video_ioctl2,
126: };
127:
128: static void usb_si4713_video_device_release(struct v4l2_device *v4l2_dev)
129: {
130: struct si4713_usb_device *radio = to_si4713_dev(v4l2_dev);
131: struct i2c_adapter *adapter = &radio->i2c_adapter;
132:
133: i2c_del_adapter(adapter);
134: v4l2_device_unregister(&radio->v4l2_dev);
135: kfree(radio->buffer);
136: kfree(radio);
137: }
138:
139: /*
140: * This command sequence emulates the behaviour of the Windows driver.
141: * The structure of these commands was determined by sniffing the
142: * usb traffic of the device during startup.
143: * Most likely, these commands make some queries to the device.
144: * Commands are sent to enquire parameters like the bus mode,
145: * component revision, boot mode, the device serial number etc.
146: *
147: * These commands are necessary to be sent in this order during startup.
148: * The device fails to powerup if these commands are not sent.
149: *
150: * The complete list of startup commands is given in the start_seq table below.
151: */
152: static int si4713_send_startup_command(struct si4713_usb_device *radio)
153: {
154: unsigned long until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1;
155: u8 *buffer = radio->buffer;
156: int retval;
157:
158: /* send the command */
159: retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
160: 0x09, 0x21, 0x033f, 0, radio->buffer,
161: BUFFER_LENGTH, USB_TIMEOUT);
162: if (retval < 0)
163: return retval;
164:
165: for (;;) {
166: /* receive the response */
167: retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
168: 0x01, 0xa1, 0x033f, 0, radio->buffer,
169: BUFFER_LENGTH, USB_TIMEOUT);
170: if (retval < 0)
171: return retval;
172: if (!radio->buffer[1]) {
173: /* USB traffic sniffing showed that some commands require
174: * additional checks. */
175: switch (buffer[1]) {
176: case 0x32:
177: if (radio->buffer[2] == 0)
178: return 0;
179: break;
180: case 0x14:
181: case 0x12:
182: if (radio->buffer[2] & SI4713_CTS)
183: return 0;
184: break;
185: case 0x06:
186: if ((radio->buffer[2] & SI4713_CTS) && radio->buffer[9] == 0x08)
187: return 0;
188: break;
189: default:
190: return 0;
191: }
192: }
193: if (time_is_before_jiffies(until_jiffies))
194: return -EIO;
195: msleep(3);
196: }
197:
198: return retval;
199: }
]
|
| 249/2 |
2026/07/30 12:50 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 161639
output: 52
thoughts: 60
Thoughts: **Analyzing the `si4713` Probe Sequence**
Okay, hold on a second. I'm recalling something important about the `si4713` device during its startup sequence. It actually transmits control messages, right? I'm thinking about `si4713_send_startup_command` specifically. And if those commands don't receive the anticipated responses, that could lead to a probe failure. This is something I've seen before with similar devices.
So, where does that leave us? Right, the next logical step is to delve into the `usb_si4713_probe` function. I need to refresh my memory on the interactions there to see if we can identify where the communication is going awry. I'll need to look at the exact timing and sequencing of messages in that probe function to see if they line up with what I'm expecting. This will likely give us the key to debugging this probing issue.
|
| 250/2 |
2026/07/30 12:50 |
tool |
read-file |
0m
Args: map[File:drivers/media/radio/si4713/radio-usb-si4713.c FirstLine:200 LineCount:100]
Results: map[Contents: 200:
201: struct si4713_start_seq_table {
202: int len;
203: u8 payload[8];
204: };
205:
206: /*
207: * Some of the startup commands that could be recognized are :
208: * (0x03): Get serial number of the board (Response : CB000-00-00)
209: * (0x06, 0x03, 0x03, 0x08, 0x01, 0x0f) : Get Component revision
210: */
211: static const struct si4713_start_seq_table start_seq[] = {
212:
213: { 1, { 0x03 } },
214: { 2, { 0x32, 0x7f } },
215: { 6, { 0x06, 0x03, 0x03, 0x08, 0x01, 0x0f } },
216: { 2, { 0x14, 0x02 } },
217: { 2, { 0x09, 0x90 } },
218: { 3, { 0x08, 0x90, 0xfa } },
219: { 2, { 0x36, 0x01 } },
220: { 2, { 0x05, 0x03 } },
221: { 7, { 0x06, 0x00, 0x06, 0x0e, 0x01, 0x0f, 0x05 } },
222: { 1, { 0x12 } },
223: /* Commands that are sent after pressing the 'Initialize'
224: button in the windows application */
225: { 1, { 0x03 } },
226: { 1, { 0x01 } },
227: { 2, { 0x09, 0x90 } },
228: { 3, { 0x08, 0x90, 0xfa } },
229: { 1, { 0x34 } },
230: { 2, { 0x35, 0x01 } },
231: { 2, { 0x36, 0x01 } },
232: { 2, { 0x30, 0x09 } },
233: { 4, { 0x30, 0x06, 0x00, 0xe2 } },
234: { 3, { 0x31, 0x01, 0x30 } },
235: { 3, { 0x31, 0x04, 0x09 } },
236: { 2, { 0x05, 0x02 } },
237: { 6, { 0x06, 0x03, 0x03, 0x08, 0x01, 0x0f } },
238: };
239:
240: static int si4713_start_seq(struct si4713_usb_device *radio)
241: {
242: int retval = 0;
243: int i;
244:
245: radio->buffer[0] = 0x3f;
246:
247: for (i = 0; i < ARRAY_SIZE(start_seq); i++) {
248: int len = start_seq[i].len;
249: const u8 *payload = start_seq[i].payload;
250:
251: memcpy(radio->buffer + 1, payload, len);
252: memset(radio->buffer + len + 1, 0, BUFFER_LENGTH - 1 - len);
253: retval = si4713_send_startup_command(radio);
254: }
255:
256: return retval;
257: }
258:
259: static struct i2c_board_info si4713_board_info = {
260: I2C_BOARD_INFO("si4713", SI4713_I2C_ADDR_BUSEN_HIGH),
261: };
262:
263: struct si4713_command_table {
264: int command_id;
265: u8 payload[8];
266: };
267:
268: /*
269: * Structure of a command :
270: * Byte 1 : 0x3f (always)
271: * Byte 2 : 0x06 (send a command)
272: * Byte 3 : Unknown
273: * Byte 4 : Number of arguments + 1 (for the command byte)
274: * Byte 5 : Number of response bytes
275: */
276: static struct si4713_command_table command_table[] = {
277:
278: { SI4713_CMD_POWER_UP, { 0x00, SI4713_PWUP_NARGS + 1, SI4713_PWUP_NRESP} },
279: { SI4713_CMD_GET_REV, { 0x03, 0x01, SI4713_GETREV_NRESP } },
280: { SI4713_CMD_POWER_DOWN, { 0x00, 0x01, SI4713_PWDN_NRESP} },
281: { SI4713_CMD_SET_PROPERTY, { 0x00, SI4713_SET_PROP_NARGS + 1, SI4713_SET_PROP_NRESP } },
282: { SI4713_CMD_GET_PROPERTY, { 0x00, SI4713_GET_PROP_NARGS + 1, SI4713_GET_PROP_NRESP } },
283: { SI4713_CMD_TX_TUNE_FREQ, { 0x03, SI4713_TXFREQ_NARGS + 1, SI4713_TXFREQ_NRESP } },
284: { SI4713_CMD_TX_TUNE_POWER, { 0x03, SI4713_TXPWR_NARGS + 1, SI4713_TXPWR_NRESP } },
285: { SI4713_CMD_TX_TUNE_MEASURE, { 0x03, SI4713_TXMEA_NARGS + 1, SI4713_TXMEA_NRESP } },
286: { SI4713_CMD_TX_TUNE_STATUS, { 0x00, SI4713_TXSTATUS_NARGS + 1, SI4713_TXSTATUS_NRESP } },
287: { SI4713_CMD_TX_ASQ_STATUS, { 0x03, SI4713_ASQSTATUS_NARGS + 1, SI4713_ASQSTATUS_NRESP } },
288: { SI4713_CMD_GET_INT_STATUS, { 0x03, 0x01, SI4713_GET_STATUS_NRESP } },
289: { SI4713_CMD_TX_RDS_BUFF, { 0x03, SI4713_RDSBUFF_NARGS + 1, SI4713_RDSBUFF_NRESP } },
290: { SI4713_CMD_TX_RDS_PS, { 0x00, SI4713_RDSPS_NARGS + 1, SI4713_RDSPS_NRESP } },
291: };
292:
293: static int send_command(struct si4713_usb_device *radio, u8 *payload, char *data, int len)
294: {
295: int retval;
296:
297: radio->buffer[0] = 0x3f;
298: radio->buffer[1] = 0x06;
299:
]
|
| 251/2 |
2026/07/30 12:50 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 164322
output: 738
thoughts: 1674
Thoughts: **USB Device Communication Analysis and Strategy**
Okay, so `si4713_send_startup_command` is the key function here. It sends control messages and expects specific responses, which is crucial for probing. The problem is that `syz_usb_connect` doesn't provide the control message responses. `syz_usb_control_io`, on the other hand, *does* handle those responses. But `syz_usb_connect` handles the initial connection, so I can't completely bypass it. If `syz_usb_connect` is used, then the tool will automatically handle the standard requests, but not the vendor-specific ones.
`si4713_send_startup_command` sends a `SET_REPORT` (0x09, 0x21, 0x033f, 0) and then receives a `GET_REPORT` (0x01, 0xa1, 0x033f, 0). If the syzkaller doesn't respond to `GET_REPORT`, the probe will fail.
Good, `syz_usb_connect$hid` *does* respond to `HID_REQ_GET_REPORT`! I need to ensure it provides the right response. Looking at `vusb_responses_hid`, I see that `HID_REQ_GET_REPORT` is covered, which is what I want.
The next thing is that `si4713_send_startup_command` checks `radio->buffer`. Specifically, it checks `if (!radio->buffer[1])`, and then it checks the `switch (buffer[1])`. This is the important part! The first comparison is comparing if byte 1 of buffer is 0. But if byte 1 is 0, the switch statement will never match!
Wait! I re-examined the code. I realized that if `radio->buffer[1]` is 0, it *succeeds* because the `default` case returns 0! Therefore, if `syz_usb_control_io$hid` returns a buffer of zeros for `HID_REQ_GET_REPORT`, `si4713_send_startup_command` will succeed because of the `default: return 0;` branch.
The next is about setting the `idVendor` and `idProduct`. Ideally, I'd want to set it to `0x10c4:0x8244`. `syz_usb_connect$hid` automatically patches those values, so I can't force it. The `syz_usb_connect` returns `fd_usb`, which isn't the same type as `syz_usb_control_io$hid`, which takes `fd_usb_hid`. But I can use `syz_usb_control_io` instead of the HID version! I can use `vusb_responses`.
I'll build the `vusb_responses` structure. I can provide a generic response for `USB_TYPE_CLASS` and `GET_REPORT` which is `0x01`. `USB_TYPE_CLASS` is `0x20`, so `type = 0x20` and `req = 0x01`. Now, let's try configuring the `vusb_responses` and supplying zero bytes of data to that `GET_REPORT` request, and see if it works!
|
| 252/2 |
2026/07/30 12:50 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{0, 0, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{0, 0, AUTO, AUTO, 0, 0, 0x80, 0, "", [{{{0, 0, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}]}}]}}, 0)
syz_usb_control_io(r0, 0, &AUTO={AUTO, @generic={0x20, 0x01, AUTO, [0, 0, 0, 0, 0, 0, 0, 0]}})
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 253/2 |
2026/07/30 12:50 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 167648
output: 739
thoughts: 531
Thoughts: **Debugging USB Descriptor Initialization**
Okay, hold on a second. I'm getting a "wrong struct arg for 'const'" error at index 0 for `bLength` in `usb_interface_descriptor_verbose_t`. Right, I remember now! `bLength` is defined as `const[USB_DT_INTERFACE_SIZE, int8]`. And `USB_DT_INTERFACE_SIZE` is, in this case, 9. So it's expecting `9`, not `0` for that field. Makes sense. I need to ensure I'm providing the correct constant values for the fields defined as `const`. I should probably double-check all the `const` fields in the other descriptors, just to be sure. Let's do a quick run-through.
First, the `usb_device_descriptor_verbose_t`:
1. `bLength` should be `USB_DT_DEVICE_SIZE`, which is 18.
2. `bDescriptorType` is `USB_DT_DEVICE`, which is 1.
3. `bcdUSB` will be 0x200.
4. `bDeviceClass` is 0,
5. `bDeviceSubClass` is 0,
6. `bDeviceProtocol` is 0,
7. `bMaxPacketSize0` is 64.
8. `idVendor` is 0x10c4.
9. `idProduct` is 0x8244.
10. `bcdDevice` is 0.
11. `iManufacturer` is 0.
12. `iProduct` is 0.
13. `iSerialNumber` is 0.
Now, the `usb_config_descriptor_verbose_t`:
1. `bLength` is `USB_DT_CONFIG_SIZE`, which is 9.
2. `bDescriptorType` is `USB_DT_CONFIG`, which is 2.
3. `wTotalLength` I'll have the system calculate.
4. `bNumInterfaces` should also be determined by the system.
5. `bConfigurationValue` is 1.
6. `iConfiguration` is 0.
7. `bmAttributes` is 0x80.
8. `bMaxPower` is 0.
Finally, back to the `usb_interface_descriptor_verbose_t`:
1. `bLength` is `USB_DT_INTERFACE_SIZE`, which, again, is 9.
2. `bDescriptorType` is `USB_DT_INTERFACE`, which is 4.
3. `bInterfaceNumber` is 0.
4. `bAlternateSetting` is 0.
5. `bNumEndpoints` this will need to be decided by the system.
6. `bInterfaceClass` is 3.
7. `bInterfaceSubClass` is 0.
8. `bInterfaceProtocol` is 0.
9. `iInterface` is 0.
Alright, I think I've got all the correct values assigned. Time to try this now. Hopefully, that will fix the issue.
|
| 254/2 |
2026/07/30 12:51 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{18, 1, 0x200, 0, 0, 0, 64, 0x10c4, 0x8244, 0, 0, 0, 0, AUTO, [{{9, 2, AUTO, AUTO, 1, 0, 0x80, 0, "", [{{{9, 4, 0, 0, AUTO, 3, 0, 0, 0, [], []}}}]}}]}}, 0)
syz_usb_control_io(r0, 0, &AUTO={AUTO, @generic={0x20, 0x01, AUTO, [0, 0, 0, 0, 0, 0, 0, 0]}})
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 255/2 |
2026/07/30 12:51 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 169814
output: 50
thoughts: 1727
Thoughts: **Analyzing USB Device Descriptor Issues**
Okay, so I'm digging into this code and I've hit a snag with the `usb_interface_descriptor_verbose_t` struct, specifically at `bLength` when dealing with the `const` argument. It looks like `usb_interface_descriptor` has a nested structure, with `usb_interface_descriptor_eps_array_t` and further down the line, `usb_interface_descriptor_t`, where `CLASS` is defined as `const[0, int8]`. This means `bInterfaceClass` *must* be `0`! But I'm providing `3`, which is clearly wrong.
I need to understand what's being passed:
1. `bLength = 9`
2. `bDescriptorType = 4`
3. `bInterfaceNumber = 0`
4. `bAlternateSetting = 0`
5. `bNumEndpoints = AUTO`
6. `bInterfaceClass = 0 (MUST BE 0!)`
7. `bInterfaceSubClass = 0`
8. `bInterfaceProtocol = 0`
9. `iInterface = 0`
10. `extra = []`
11. `endpoints = []`
If `bInterfaceClass` is forced to `0`, I can't just pass `3` for a HID device class (`USB_CLASS_HID`) like `si4713` expects. I was hoping to use `syz_usb_connect$hid`, but that also hardcodes vendor and product IDs. Maybe I can use `syz_usb_connect$hid` and *somehow* have it patch the IDs to match `si4713`? No, Syzkaller patches it to specific IDs. I need to make sure I am providing the right IDs! Let me check `drivers/media/radio/si4713/radio-usb-si4713.c` again. Yes, it uses `USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT, USB_CLASS_HID, 0, 0)`.
What are my options? I could use `syz_usb_connect` with a `usb_device_descriptor`, but it's hardcoded to `0` for the interface class. Okay, I was trying to send an array of bytes, but I know it'll cause an error. I can use the `ANY` type in syzkaller.
I can't directly use `ANY` like that. I can use `syz_usb_connect$hid`! But that takes `usb_device_descriptor_hid`. The inner `usb_device_descriptor_t` in `usb_device_descriptor_hid` has `VENDOR` and `PRODUCT` at `0, 0`. Okay, syzkaller will patch them. This sounds promising! But will it work and is my target still `si4713`?
I need to re-evaluate my options: if I use `syz_usb_connect$hid`, syzkaller *will* patch `idVendor` and `idProduct`. If I *also* open `/dev/radio0`, will that trigger the bug? The bug is in `i2c_adapter_depth`, which calls `i2c_adapter_lock_bus`. I need to trigger a UAF on `adapter->dev.parent->type`. I know this happens when an I2C adapter is unregistered, but its parent (`usb_device`) is already freed.
So, the key is the I2C adapter and the driver. `si4713` *is* one such driver. Wait! I remember I found it in `au0828`. Let's check `au0828`. It's a video driver, and it *does* register an I2C adapter, and it has the same UAF issue! I've been here before. Now, what USB IDs does `au0828` use? Ah, `0x2040:0x7200`. Can I use `syz_usb_connect` here?
`au0828` expects either `0` or `255` for `bDeviceClass`. Let's check its USB device table. It uses `USB_DEVICE(0x2040, 0x7200)`, which matches *any* class! Perfect! So, if I use `syz_usb_connect` with `idVendor=0x2040` and `idProduct
|
| 256/2 |
2026/07/30 12:51 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:200 LineCount:100]
Results: map[Contents: 200:
201: mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE);
202: if (IS_ERR(mdev))
203: return PTR_ERR(mdev);
204:
205: dev->media_dev = mdev;
206: #endif
207: return 0;
208: }
209:
210: #ifdef CONFIG_MEDIA_CONTROLLER
211: static void au0828_media_graph_notify(struct media_entity *new,
212: void *notify_data)
213: {
214: struct au0828_dev *dev = notify_data;
215: int ret;
216: struct media_entity *entity, *mixer = NULL, *decoder = NULL;
217:
218: if (!new) {
219: /*
220: * Called during au0828 probe time to connect
221: * entities that were created prior to registering
222: * the notify handler. Find mixer and decoder.
223: */
224: media_device_for_each_entity(entity, dev->media_dev) {
225: if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
226: mixer = entity;
227: else if (entity->function == MEDIA_ENT_F_ATV_DECODER)
228: decoder = entity;
229: }
230: goto create_link;
231: }
232:
233: switch (new->function) {
234: case MEDIA_ENT_F_AUDIO_MIXER:
235: mixer = new;
236: if (dev->decoder)
237: decoder = dev->decoder;
238: break;
239: case MEDIA_ENT_F_ATV_DECODER:
240: /* In case, Mixer is added first, find mixer and create link */
241: media_device_for_each_entity(entity, dev->media_dev) {
242: if (entity->function == MEDIA_ENT_F_AUDIO_MIXER)
243: mixer = entity;
244: }
245: decoder = new;
246: break;
247: default:
248: break;
249: }
250:
251: create_link:
252: if (decoder && mixer) {
253: ret = media_get_pad_index(decoder, MEDIA_PAD_FL_SOURCE,
254: PAD_SIGNAL_AUDIO);
255: if (ret >= 0)
256: ret = media_create_pad_link(decoder, ret,
257: mixer, 0,
258: MEDIA_LNK_FL_ENABLED);
259: if (ret < 0)
260: dev_err(&dev->usbdev->dev,
261: "Mixer Pad Link Create Error: %d\n", ret);
262: }
263: }
264:
265: static bool au0828_is_link_shareable(struct media_entity *owner,
266: struct media_entity *entity)
267: {
268: bool shareable = false;
269:
270: /* Tuner link can be shared by audio, video, and VBI */
271: switch (owner->function) {
272: case MEDIA_ENT_F_IO_V4L:
273: case MEDIA_ENT_F_AUDIO_CAPTURE:
274: case MEDIA_ENT_F_IO_VBI:
275: if (entity->function == MEDIA_ENT_F_IO_V4L ||
276: entity->function == MEDIA_ENT_F_AUDIO_CAPTURE ||
277: entity->function == MEDIA_ENT_F_IO_VBI)
278: shareable = true;
279: break;
280: case MEDIA_ENT_F_DTV_DEMOD:
281: default:
282: break;
283: }
284: return shareable;
285: }
286:
287: /* Callers should hold graph_mutex */
288: static int au0828_enable_source(struct media_entity *entity,
289: struct media_pipeline *pipe)
290: {
291: struct media_entity *source, *find_source;
292: struct media_entity *sink;
293: struct media_link *link, *found_link = NULL;
294: int ret = 0;
295: struct media_device *mdev = entity->graph_obj.mdev;
296: struct au0828_dev *dev;
297:
298: if (!mdev)
299: return -ENODEV;
]
|
| 257/2 |
2026/07/30 12:51 |
llm |
crash-repro-finder-compressor |
10m
Model:
Reply: ### 1. Approaches Tried and Results
* **Device Path Opening**:
* Attempted to open `/dev/video0` and `/dev/i2c-0` directly using `syz_open_dev$video` and `syz_open_dev$I2C` with explicit paths.
* *Result*: Failed with `bad string value "/dev/video0\x00", expect ["/dev/video#\x00"]`.
* *Correction*: Syzkaller requires the exact template string `"/dev/video#\x00"` or `"/dev/i2c-#\x00"`, replacing `#` with the `id` argument.
* **Generic HID Emulation**:
* Used `syz_usb_connect$hid` to connect a generic HID device.
* *Result*: No crash. Coverage analysis showed `raw_gadget.c` was covered, but target drivers (`si4713`, `au0828`, `go7007`) were not. This is because `syz_usb_connect$hid` patches vendor/product IDs to match generic HID drivers, not our target drivers.
* **Custom USB Descriptor Construction**:
* Attempted to construct a custom `usb_device_descriptor` for `syz_usb_connect` to emulate `si4713` (Vendor `0x10c4`, Product `0x8244`, Class `USB_CLASS_HID`).
* *Dead-ends & Syntax Errors*:
* `AUTO` cannot be used for `FlagsType` (e.g., `bcdUSB`, `bMaxPacketSize0`, `bmAttributes`). They must be explicit values (e.g., `0x200`, `64`, `0x80`).
* `AUTO` cannot be used for `ArrayType` (e.g., `configs`, `interfaces`). They must be explicit arrays (e.g., `[...]`).
* `void` fields (like `extra` in `usb_config_descriptor_verbose_t`) are omitted and do not accept `{}`.
* `len` fields (like `bNumConfigurations`, `wTotalLength`, `bNumInterfaces`, `bNumEndpoints`) are of `LenType` and must be explicitly provided as `AUTO` in the struct literal (they are NOT omitted).
* `usb_interface_descriptor` is a struct with a single field `inner`, requiring nested braces `{{{...}}}` for its array elements.
* Currently blocked on a persistent `wrong array arg *prog.BufferType` or `wrong array arg *prog.LenType` error when trying to correctly nest the `interfaces` array inside the `configs` array of the `usb_device_descriptor`.
### 2. Current Hypotheses & Active Lines of Investigation
* **Deferred Cleanup Race via `si4713`**:
* Emulate a USB device matching `si4713` (Vendor `0x10c4`, Product `0x8244`, Class `USB_CLASS_HID`).
* Open the corresponding radio device `/dev/radio#` to hold a reference to the driver context.
* Open the corresponding I2C device `/dev/i2c-#`.
* Disconnect the USB device. The driver's `disconnect` callback runs but defers the unregistration of the I2C adapter because the radio device is still open.
* The USB core frees the `struct usb_device`.
* Perform an I2C transaction (e.g., `ioctl$I2C_SMBUS`) on the open I2C file descriptor. This triggers `i2c_adapter_depth` which dereferences `adapter->dev.parent->type` (offset 264 of the freed `usb_device`), causing the UAF.
### 3. Critical Code and Configuration Values
* **Target USB IDs**:
* `si4713`: Vendor `0x10c4`, Product `0x8244`, Class `3` (`USB_CLASS_HID`).
* `au0828`: Vendor `0x2040`, Product `0x7200`.
* `go7007`: Vendor `0x0eb1`, Product `0x7007`.
* **Syzkaller Struct Definitions (from `vusb.txt`)**:
```
usb_device_descriptor {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]]
} [packed]
usb_config_descriptor {
inner usb_config_descriptor_ifaces_array_t[int8, array[usb_interface_descriptor, 1:4]]
} [packed]
usb_interface_descriptor {
inner usb_interface_descriptor_eps_array_t[int8, int8, const[0, int8], const[0, int8], const[0, int8], array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
} [packed]
```
* **Field Counts for Struct Literals**:
* `usb_device_descriptor_verbose_t` (15 fields):
`bLength` (const), `bDescriptorType` (const), `bcdUSB` (flags), `bDeviceClass` (const), `bDeviceSubClass` (const), `bDeviceProtocol` (const), `bMaxPacketSize0` (flags), `idVendor` (const), `idProduct` (const), `bcdDevice` (const), `iManufacturer` (const), `iProduct` (const), `iSerialNumber` (const), `bNumConfigurations` (len), `configs` (array).
* `usb_config_descriptor_verbose_t` (10 fields, `extra` is `void` and omitted -> 9 fields):
`bLength` (const), `bDescriptorType` (const), `wTotalLength` (len), `bNumInterfaces` (len), `bConfigurationValue` (int), `iConfiguration` (int), `bmAttributes` (flags), `bMaxPower` (int), `interfaces` (array).
* `usb_interface_descriptor_verbose_t` (11 fields):
`bLength` (const), `bDescriptorType` (const), `bInterfaceNumber` (int), `bAlternateSetting` (int), `bNumEndpoints` (len), `bInterfaceClass` (const), `bInterfaceSubClass` (const), `bInterfaceProtocol` (const), `iInterface` (int), `extra` (array), `endpoints` (array).
### 4. Potential Reasoning Loops / Repetitive Tool Calls
* **Brace Nesting Loop**: Avoid repeatedly guessing the brace nesting of `configs` and `interfaces` arrays in `usb_device_descriptor` without matching the exact field types.
* **Omitted vs. Non-Omitted Fields**: Remember that `len` fields (of `LenType`) are NOT omitted in syzkaller program syntax; they must be explicitly provided as `AUTO`. Only `void` fields are omitted. All `const`, `int`, and `flags` fields must have explicit values (or `0` if they are not important).
Tokens:
input: 160864
output: 1690
thoughts: 3189
|
| 258/2 |
2026/07/30 13:01 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 43759
output: 50
thoughts: 18
Thoughts: Okay, let's see. My mind's jumping around a bit, but the most pressing thing right now is that `au0828_usb_probe`. I need to get back to that. It's calling to me, you know? It's the key to something I'm working on, and I've got to revisit the code for it immediately. I need to dive back in and understand what's happening.
|
| 259/2 |
2026/07/30 13:02 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:580 LineCount:100]
Results: map[Contents: 580: }
581: } else {
582: /*
583: * Call au0828_media_graph_notify() to connect
584: * audio graph to our graph. In this case, audio
585: * driver registered the device and there is no
586: * entity_notify to be called when new entities
587: * are added. Invoke it now.
588: */
589: au0828_media_graph_notify(NULL, (void *) dev);
590: }
591:
592: /*
593: * Find tuner, decoder and demod.
594: *
595: * The tuner and decoder should be cached, as they'll be used by
596: * au0828_enable_source.
597: *
598: * It also needs to disable the link between tuner and
599: * decoder/demod, to avoid disable step when tuner is requested
600: * by video or audio. Note that this step can't be done until dvb
601: * graph is created during dvb register.
602: */
603: media_device_for_each_entity(entity, dev->media_dev) {
604: switch (entity->function) {
605: case MEDIA_ENT_F_TUNER:
606: dev->tuner = entity;
607: break;
608: case MEDIA_ENT_F_ATV_DECODER:
609: dev->decoder = entity;
610: break;
611: case MEDIA_ENT_F_DTV_DEMOD:
612: demod = entity;
613: break;
614: }
615: }
616:
617: /* Disable link between tuner->demod and/or tuner->decoder */
618: if (dev->tuner) {
619: list_for_each_entry(link, &dev->tuner->links, list) {
620: if (demod && link->sink->entity == demod)
621: media_entity_setup_link(link, 0);
622: if (dev->decoder && link->sink->entity == dev->decoder)
623: media_entity_setup_link(link, 0);
624: }
625: }
626:
627: /* register entity_notify callback */
628: dev->entity_notify.notify_data = (void *) dev;
629: dev->entity_notify.notify = (void *) au0828_media_graph_notify;
630: media_device_register_entity_notify(dev->media_dev,
631: &dev->entity_notify);
632:
633: /* set enable_source */
634: mutex_lock(&dev->media_dev->graph_mutex);
635: dev->media_dev->source_priv = (void *) dev;
636: dev->media_dev->enable_source = au0828_enable_source;
637: dev->media_dev->disable_source = au0828_disable_source;
638: mutex_unlock(&dev->media_dev->graph_mutex);
639: #endif
640: return 0;
641: }
642:
643: static int au0828_usb_probe(struct usb_interface *interface,
644: const struct usb_device_id *id)
645: {
646: int ifnum;
647: int retval = 0;
648:
649: struct au0828_dev *dev;
650: struct usb_device *usbdev = interface_to_usbdev(interface);
651:
652: ifnum = interface->altsetting->desc.bInterfaceNumber;
653:
654: if (ifnum != 0)
655: return -ENODEV;
656:
657: dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
658: le16_to_cpu(usbdev->descriptor.idVendor),
659: le16_to_cpu(usbdev->descriptor.idProduct),
660: ifnum);
661:
662: /*
663: * Make sure we have 480 Mbps of bandwidth, otherwise things like
664: * video stream wouldn't likely work, since 12 Mbps is generally
665: * not enough even for most Digital TV streams.
666: */
667: if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
668: pr_err("au0828: Device initialization failed.\n");
669: pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
670: return -ENODEV;
671: }
672:
673: dev = kzalloc_obj(*dev);
674: if (dev == NULL) {
675: pr_err("%s() Unable to allocate memory\n", __func__);
676: return -ENOMEM;
677: }
678:
679: mutex_init(&dev->lock);
]
|
| 260/2 |
2026/07/30 13:02 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 45492
output: 50
thoughts: 104
Thoughts: **Debugging the `au0828` USB Driver Connection**
Okay, let's see... the error log points to `au0828` needing a `USB_SPEED_HIGH` connection, specifically `usbdev->speed == USB_SPEED_HIGH`. I remember `syz_usb_connect` takes a `speed` argument using the `flags[usb_device_speed]` enum. Let me check... Ah, right, `USB_SPEED_HIGH` is defined as `3`. I'm pretty sure I provided `3` in the test case. And the interface number, `ifnum`, must be `0`, which I explicitly set to `bInterfaceNumber = 0`. So far, so good, I think the speed and interface number are correct.
Wait a second... it can't be that simple. What about the endpoints? I wonder if `au0828` has specific checks related to the endpoint configurations during the connection process. It's time to dig deeper into the driver code related to endpoint handling to understand why this connection is failing.
|
| 261/2 |
2026/07/30 13:02 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:680 LineCount:100]
Results: map[Contents: 680: mutex_lock(&dev->lock);
681: mutex_init(&dev->mutex);
682: mutex_init(&dev->dvb.lock);
683: dev->usbdev = usbdev;
684: dev->boardnr = id->driver_info;
685: dev->board = au0828_boards[dev->boardnr];
686:
687: /* Initialize the media controller */
688: retval = au0828_media_device_init(dev, usbdev);
689: if (retval) {
690: pr_err("%s() au0828_media_device_init failed\n",
691: __func__);
692: mutex_unlock(&dev->lock);
693: kfree(dev);
694: return retval;
695: }
696:
697: retval = au0828_v4l2_device_register(interface, dev);
698: if (retval) {
699: au0828_usb_v4l2_media_release(dev);
700: mutex_unlock(&dev->lock);
701: kfree(dev);
702: return retval;
703: }
704:
705: /* Power Up the bridge */
706: au0828_write(dev, REG_600, 1 << 4);
707:
708: /* Bring up the GPIO's and supporting devices */
709: au0828_gpio_setup(dev);
710:
711: /* I2C */
712: au0828_i2c_register(dev);
713:
714: /* Setup */
715: au0828_card_setup(dev);
716:
717: /*
718: * Store the pointer to the au0828_dev so it can be accessed in
719: * au0828_usb_disconnect
720: */
721: usb_set_intfdata(interface, dev);
722:
723: /* Analog TV */
724: retval = au0828_analog_register(dev, interface);
725: if (retval) {
726: pr_err("%s() au0828_analog_register failed to register on V4L2\n",
727: __func__);
728: mutex_unlock(&dev->lock);
729: goto done;
730: }
731:
732: /* Digital TV */
733: retval = au0828_dvb_register(dev);
734: if (retval)
735: pr_err("%s() au0828_dvb_register failed\n",
736: __func__);
737:
738: /* Remote controller */
739: au0828_rc_register(dev);
740:
741: pr_info("Registered device AU0828 [%s]\n",
742: dev->board.name == NULL ? "Unset" : dev->board.name);
743:
744: mutex_unlock(&dev->lock);
745:
746: retval = au0828_media_device_register(dev, usbdev);
747:
748: done:
749: if (retval < 0)
750: au0828_usb_disconnect(interface);
751:
752: return retval;
753: }
754:
755: static int au0828_suspend(struct usb_interface *interface,
756: pm_message_t message)
757: {
758: struct au0828_dev *dev = usb_get_intfdata(interface);
759:
760: if (!dev)
761: return 0;
762:
763: pr_info("Suspend\n");
764:
765: au0828_rc_suspend(dev);
766: au0828_v4l2_suspend(dev);
767: au0828_dvb_suspend(dev);
768:
769: /* FIXME: should suspend also ATV/DTV */
770:
771: return 0;
772: }
773:
774: static int au0828_resume(struct usb_interface *interface)
775: {
776: struct au0828_dev *dev = usb_get_intfdata(interface);
777: if (!dev)
778: return 0;
779:
]
|
| 262/2 |
2026/07/30 13:02 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 47297
output: 52
thoughts: 47
Thoughts: **Analyzing the Code's I2C Registration**
Okay, so looking at this code snippet, the first thing that jumps out at me is that it appears to bypass the usual endpoint checks. It doesn't seem to be performing any validation before attempting to register with the I2C bus. Instead, it jumps straight to `au0828_i2c_register(dev)`. That's a bit unusual. My immediate thought is, "Why the shortcut?" Is this intended behaviour, or is something being assumed?
I need to dive deeper. My next step will be to meticulously examine the `au0828_i2c_register` function itself. I need to understand what it's doing internally. Does it handle any error checking or validation *within* that function? Does it assume the `dev` structure is valid at this point? Does it perform the equivalent of what was skipped above, or does it do something else entirely? A thorough investigation of `au0828_i2c_register` will provide crucial context and hopefully illuminate why this initial code doesn't seem to be performing endpoint checks before the I2C registration.
|
| 263/2 |
2026/07/30 13:02 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-i2c.c FirstLine:350 LineCount:100]
Results: map[Contents: 350: }
351: }
352:
353: /* init + register i2c adapter */
354: int au0828_i2c_register(struct au0828_dev *dev)
355: {
356: dprintk(1, "%s()\n", __func__);
357:
358: dev->i2c_adap = au0828_i2c_adap_template;
359: dev->i2c_algo = au0828_i2c_algo_template;
360: dev->i2c_client = au0828_i2c_client_template;
361:
362: dev->i2c_adap.dev.parent = &dev->usbdev->dev;
363:
364: strscpy(dev->i2c_adap.name, KBUILD_MODNAME,
365: sizeof(dev->i2c_adap.name));
366:
367: dev->i2c_adap.algo = &dev->i2c_algo;
368: dev->i2c_adap.algo_data = dev;
369: #ifdef CONFIG_VIDEO_AU0828_V4L2
370: i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
371: #else
372: i2c_set_adapdata(&dev->i2c_adap, dev);
373: #endif
374: i2c_add_adapter(&dev->i2c_adap);
375:
376: dev->i2c_client.adapter = &dev->i2c_adap;
377:
378: if (0 == dev->i2c_rc) {
379: pr_info("i2c bus registered\n");
380: if (i2c_scan)
381: do_i2c_scan(KBUILD_MODNAME, &dev->i2c_client);
382: } else
383: pr_info("i2c bus register FAILED\n");
384:
385: return dev->i2c_rc;
386: }
387:
388: int au0828_i2c_unregister(struct au0828_dev *dev)
389: {
390: i2c_del_adapter(&dev->i2c_adap);
391: return 0;
392: }
393:
]
|
| 264/2 |
2026/07/30 13:02 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 48392
output: 50
thoughts: 42
Thoughts: Okay, here's my interpretation of those thoughts, framed from my perspective as an expert:
**Debugging the I2C Adapter**
Alright, that's a good start - the system *is* recognizing the I2C adapter. The core hardware link appears to be established. Now, the gears are turning... I need to be careful not to make assumptions. Is this a *specific* issue with this particular adapter, or is there a more general flaw in the I2C driver implementation?
That `au0828` driver... could it be exhibiting the same disconnection bug I've seen before? I remember there was a problem with handling USB disconnect events, and this is a prime suspect. Let's dig into that `au0828_usb_disconnect` function. Understanding how that function handles the disconnection of the USB device is crucial. Checking that function should help provide further insight into whether this is a general I2C driver issue or something specific to this implementation. Time to look closely at that code and trace the disconnect sequence.
|
| 265/2 |
2026/07/30 13:02 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:290 LineCount:100]
Results: map[Contents: 290: {
291: struct media_entity *source, *find_source;
292: struct media_entity *sink;
293: struct media_link *link, *found_link = NULL;
294: int ret = 0;
295: struct media_device *mdev = entity->graph_obj.mdev;
296: struct au0828_dev *dev;
297:
298: if (!mdev)
299: return -ENODEV;
300:
301: dev = mdev->source_priv;
302:
303: /*
304: * For Audio and V4L2 entity, find the link to which decoder
305: * is the sink. Look for an active link between decoder and
306: * source (tuner/s-video/Composite), if one exists, nothing
307: * to do. If not, look for any active links between source
308: * and any other entity. If one exists, source is busy. If
309: * source is free, setup link and start pipeline from source.
310: * For DVB FE entity, the source for the link is the tuner.
311: * Check if tuner is available and setup link and start
312: * pipeline.
313: */
314: if (entity->function == MEDIA_ENT_F_DTV_DEMOD) {
315: sink = entity;
316: find_source = dev->tuner;
317: } else {
318: /* Analog isn't configured or register failed */
319: if (!dev->decoder) {
320: ret = -ENODEV;
321: goto end;
322: }
323:
324: sink = dev->decoder;
325:
326: /*
327: * Default input is tuner and default input_type
328: * is AU0828_VMUX_TELEVISION.
329: *
330: * There is a problem when s_input is called to
331: * change the default input. s_input will try to
332: * enable_source before attempting to change the
333: * input on the device, and will end up enabling
334: * default source which is tuner.
335: *
336: * Additional logic is necessary in au0828 to detect
337: * that the input has changed and enable the right
338: * source. au0828 handles this case in its s_input.
339: * It will disable the old source and enable the new
340: * source.
341: *
342: */
343: if (dev->input_type == AU0828_VMUX_TELEVISION)
344: find_source = dev->tuner;
345: else if (dev->input_type == AU0828_VMUX_SVIDEO ||
346: dev->input_type == AU0828_VMUX_COMPOSITE)
347: find_source = &dev->input_ent[dev->input_type];
348: else {
349: /* unknown input - let user select input */
350: ret = 0;
351: goto end;
352: }
353: }
354:
355: /* Is there an active link between sink and source */
356: if (dev->active_link) {
357: if (dev->active_link_owner == entity) {
358: /* This check is necessary to handle multiple
359: * enable_source calls from v4l_ioctls during
360: * the course of video/vbi application run-time.
361: */
362: pr_debug("%s already owns the tuner\n", entity->name);
363: ret = 0;
364: goto end;
365: } else if (au0828_is_link_shareable(dev->active_link_owner,
366: entity)) {
367: /* Either ALSA or Video own tuner. Sink is the same
368: * for both. Allow sharing the active link between
369: * their common source (tuner) and sink (decoder).
370: * Starting pipeline between sharing entity and sink
371: * will fail with pipe mismatch, while owner has an
372: * active pipeline. Switch pipeline ownership from
373: * user to owner when owner disables the source.
374: */
375: dev->active_link_shared = true;
376: /* save the user info to use from disable */
377: dev->active_link_user = entity;
378: dev->active_link_user_pipe = pipe;
379: pr_debug("%s owns the tuner %s can share!\n",
380: dev->active_link_owner->name,
381: entity->name);
382: ret = 0;
383: goto end;
384: } else {
385: ret = -EBUSY;
386: goto end;
387: }
388: }
389:
]
|
| 266/2 |
2026/07/30 13:02 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 50227
output: 50
thoughts: 17
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**Navigating the USB Landscape**
Alright, hold on a second. I'm deep into this analysis, and I've hit a point where I need to take a step back and specifically examine something. The flow I'm tracing... something feels a little off. I need to zero in on a particular event to get a clearer picture of what's happening. The specific artifact I require right now is `au0828_usb_disconnect`. That's where I need to focus my attention. It's that critical point where the USB connection is severed, and I need to see *precisely* what the system is doing, or not doing, at that juncture. I suspect that's the key to understanding this current, elusive issue. Time to drill down.
|
| 267/2 |
2026/07/30 13:02 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:400 LineCount:100]
Results: map[Contents: 400: ret = -ENODEV;
401: goto end;
402: }
403:
404: /* activate link between source and sink and start pipeline */
405: source = found_link->source->entity;
406: ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED);
407: if (ret) {
408: pr_err("Activate link from %s->%s. Error %d\n",
409: source->name, sink->name, ret);
410: goto end;
411: }
412:
413: ret = __media_pipeline_start(entity->pads, pipe);
414: if (ret) {
415: pr_err("Start Pipeline: %s->%s Error %d\n",
416: source->name, entity->name, ret);
417: ret = __media_entity_setup_link(found_link, 0);
418: if (ret)
419: pr_err("Deactivate link Error %d\n", ret);
420: goto end;
421: }
422:
423: /* save link state to allow audio and video share the link
424: * and not disable the link while the other is using it.
425: * active_link_owner is used to deactivate the link.
426: */
427: dev->active_link = found_link;
428: dev->active_link_owner = entity;
429: dev->active_source = source;
430: dev->active_sink = sink;
431:
432: pr_info("Enabled Source: %s->%s->%s Ret %d\n",
433: dev->active_source->name, dev->active_sink->name,
434: dev->active_link_owner->name, ret);
435: end:
436: pr_debug("%s end: ent:%s fnc:%d ret %d\n",
437: __func__, entity->name, entity->function, ret);
438: return ret;
439: }
440:
441: /* Callers should hold graph_mutex */
442: static void au0828_disable_source(struct media_entity *entity)
443: {
444: int ret = 0;
445: struct media_device *mdev = entity->graph_obj.mdev;
446: struct au0828_dev *dev;
447:
448: if (!mdev)
449: return;
450:
451: dev = mdev->source_priv;
452:
453: if (!dev->active_link)
454: return;
455:
456: /* link is active - stop pipeline from source
457: * (tuner/s-video/Composite) to the entity
458: * When DVB/s-video/Composite owns tuner, it won't be in
459: * shared state.
460: */
461: if (dev->active_link->sink->entity == dev->active_sink &&
462: dev->active_link->source->entity == dev->active_source) {
463: /*
464: * Prevent video from deactivating link when audio
465: * has active pipeline and vice versa. In addition
466: * handle the case when more than one video/vbi
467: * application is sharing the link.
468: */
469: bool owner_is_audio = false;
470:
471: if (dev->active_link_owner->function ==
472: MEDIA_ENT_F_AUDIO_CAPTURE)
473: owner_is_audio = true;
474:
475: if (dev->active_link_shared) {
476: pr_debug("Shared link owner %s user %s %d\n",
477: dev->active_link_owner->name,
478: entity->name, dev->users);
479:
480: /* Handle video device users > 1
481: * When audio owns the shared link with
482: * more than one video users, avoid
483: * disabling the source and/or switching
484: * the owner until the last disable_source
485: * call from video _close(). Use dev->users to
486: * determine when to switch/disable.
487: */
488: if (dev->active_link_owner != entity) {
489: /* video device has users > 1 */
490: if (owner_is_audio && dev->users > 1)
491: return;
492:
493: dev->active_link_user = NULL;
494: dev->active_link_user_pipe = NULL;
495: dev->active_link_shared = false;
496: return;
497: }
498:
499: /* video owns the link and has users > 1 */
]
|
| 268/2 |
2026/07/30 13:02 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 51988
output: 23
thoughts: 18
Thoughts: Here's my thought process, summarized as you requested:
**Navigating the Digital Landscape: The Quest for `au0828_usb_disconnect`**
Okay, hold on a second. Before I get too deep into this, I need to take a step back and make sure I have all the pieces I need. My immediate priority is to locate information regarding `au0828_usb_disconnect`. This function, or code snippet, is crucial for understanding a specific aspect of this project, I'm sure of it. I need to find context, definitions, and any relevant documentation. My experience tells me that this search will probably be the key to unlocking the right answers. Let's see what I can uncover, and what that tells me.
|
| 269/2 |
2026/07/30 13:02 |
tool |
grepper |
0m
Args: map[Expression:au0828_usb_disconnect]
Results: map[Output:drivers/media/usb/au0828/au0828-core.c=153=void au0828_usb_release(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-core.c-162-
drivers/media/usb/au0828/au0828-core.c:163:static void au0828_usb_disconnect(struct usb_interface *interface)
drivers/media/usb/au0828/au0828-core.c-164-{
--
drivers/media/usb/au0828/au0828-core.c=643=static int au0828_usb_probe(struct usb_interface *interface,
--
drivers/media/usb/au0828/au0828-core.c-718- * Store the pointer to the au0828_dev so it can be accessed in
drivers/media/usb/au0828/au0828-core.c:719: * au0828_usb_disconnect
drivers/media/usb/au0828/au0828-core.c-720- */
--
drivers/media/usb/au0828/au0828-core.c-749- if (retval < 0)
drivers/media/usb/au0828/au0828-core.c:750: au0828_usb_disconnect(interface);
drivers/media/usb/au0828/au0828-core.c-751-
--
drivers/media/usb/au0828/au0828-core.c=797=static struct usb_driver au0828_usb_driver = {
--
drivers/media/usb/au0828/au0828-core.c-799- .probe = au0828_usb_probe,
drivers/media/usb/au0828/au0828-core.c:800: .disconnect = au0828_usb_disconnect,
drivers/media/usb/au0828/au0828-core.c-801- .id_table = au0828_usb_id_table,
]
|
| 270/2 |
2026/07/30 13:02 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 52797
output: 49
thoughts: 15
Thoughts: Okay, here we go...
**Diving into au0828_usb_disconnect**
Alright, let's get down to brass tacks. The prompt says "Let's read `au0828_usb_disconnect`". So, my immediate thought is, "Okay, another delve into a USB disconnect function. Given my experience, I'm expecting this is going to be a crucial piece of the driver, the linchpin that gracefully handles the removal of a USB device associated with the au0828, which I know is a popular USB device often used for video capture. I'm already anticipating the nuances of resource management that I'll need to dissect β deallocating buffers, resetting hardware, and ensuring that no race conditions arise in the driver with other threads. "
"I need to understand this disconnect procedure completely. Was this written to handle hot-plug removal? How robust is this code? Is it a bare-bones implementation, or does it incorporate sophisticated error handling and state management? I need to look for typical USB disconnection steps: issuing an `usb_kill_urb`, cancelling pending transfers, releasing any claimed USB interfaces, and potentially resetting hardware components related to the au0828. I also want to make sure the right cleanup happens, like properly shutting down the video stream and releasing all the resources so the system isn't left in a bad state."
"I hope this code doesn't leave any dangling pointers, unreleased mutexes, or orphaned memory allocations. My goal is to ensure this disconnect routine is bulletproof and doesn't introduce any instability into the system. It would also be good to think about the situation where the user unplugs the USB cable while the device is in the middle of operation. I need to keep that kind of situation in mind."
|
| 271/2 |
2026/07/30 13:02 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:160 LineCount:50]
Results: map[Contents: 160: kfree(dev);
161: }
162:
163: static void au0828_usb_disconnect(struct usb_interface *interface)
164: {
165: struct au0828_dev *dev = usb_get_intfdata(interface);
166:
167: dprintk(1, "%s()\n", __func__);
168:
169: /* there is a small window after disconnect, before
170: dev->usbdev is NULL, for poll (e.g: IR) try to access
171: the device and fill the dmesg with error messages.
172: Set the status so poll routines can check and avoid
173: access after disconnect.
174: */
175: set_bit(DEV_DISCONNECTED, &dev->dev_state);
176:
177: au0828_rc_unregister(dev);
178: /* Digital TV */
179: au0828_dvb_unregister(dev);
180:
181: usb_set_intfdata(interface, NULL);
182: mutex_lock(&dev->mutex);
183: dev->usbdev = NULL;
184: mutex_unlock(&dev->mutex);
185: if (au0828_analog_unregister(dev)) {
186: /*
187: * No need to call au0828_usb_release() if V4L2 is enabled,
188: * as this is already called via au0828_usb_v4l2_release()
189: */
190: return;
191: }
192: au0828_usb_release(dev);
193: }
194:
195: static int au0828_media_device_init(struct au0828_dev *dev,
196: struct usb_device *udev)
197: {
198: #ifdef CONFIG_MEDIA_CONTROLLER
199: struct media_device *mdev;
200:
201: mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE);
202: if (IS_ERR(mdev))
203: return PTR_ERR(mdev);
204:
205: dev->media_dev = mdev;
206: #endif
207: return 0;
208: }
209:
]
|
| 272/2 |
2026/07/30 13:02 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 53986
output: 50
thoughts: 54
Thoughts: **Analyzing the USB Disconnect Flow**
Okay, so I'm looking at this `au0828_usb_disconnect` function. Something immediately jumps out at me: it calls `au0828_analog_unregister(dev)`. And *crucially*, it returns early if that function returns true. This is important to catch. I need to understand what situations lead to `au0828_analog_unregister` returning true, because that's where the control flow diverges. I need to understand if this could cause issues. Alright, so I need to dig into the `au0828_analog_unregister` function to figure out what's going on. Let's see what that does...
|
| 273/2 |
2026/07/30 13:02 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-video.c FirstLine:1890 LineCount:50]
Results: map[Contents:1890: switch (AUVI_INPUT(i).type) {
1891: case AU0828_VMUX_COMPOSITE:
1892: ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
1893: break;
1894: case AU0828_VMUX_SVIDEO:
1895: ent->function = MEDIA_ENT_F_CONN_SVIDEO;
1896: break;
1897: case AU0828_VMUX_CABLE:
1898: case AU0828_VMUX_TELEVISION:
1899: case AU0828_VMUX_DVB:
1900: default: /* Just to shut up a warning */
1901: ent->function = MEDIA_ENT_F_CONN_RF;
1902: break;
1903: }
1904:
1905: ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
1906: if (ret < 0)
1907: pr_err("failed to initialize input pad[%d]!\n", i);
1908:
1909: ret = media_device_register_entity(dev->media_dev, ent);
1910: if (ret < 0)
1911: pr_err("failed to register input entity %d!\n", i);
1912: }
1913: #endif
1914: }
1915:
1916: /**************************************************************************/
1917:
1918: int au0828_analog_register(struct au0828_dev *dev,
1919: struct usb_interface *interface)
1920: {
1921: int retval = -ENOMEM;
1922: struct usb_host_interface *iface_desc;
1923: struct usb_endpoint_descriptor *endpoint;
1924: int i, ret;
1925:
1926: dprintk(1, "au0828_analog_register called for intf#%d!\n",
1927: interface->cur_altsetting->desc.bInterfaceNumber);
1928:
1929: /* No analog TV */
1930: if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
1931: return 0;
1932:
1933: /* set au0828 usb interface0 to as5 */
1934: retval = usb_set_interface(dev->usbdev,
1935: interface->cur_altsetting->desc.bInterfaceNumber, 5);
1936: if (retval != 0) {
1937: pr_info("Failure setting usb interface0 to as5\n");
1938: return retval;
1939: }
]
|
| 274/2 |
2026/07/30 13:02 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 55053
output: 23
thoughts: 17
Thoughts: Okay, here's my thought process on that:
**Hunting Down `au0828_analog_unregister`**
Right, so I need to find the definition or usage of `au0828_analog_unregister`. Itβs a pretty specific function name, so I'm guessing itβs related to the `au0828` driver, which from the name alone I suspect it has something to do with audio or analog video, probably in the context of a particular embedded or system-level implementation. My initial approach will be to locate the source code. I'll probably start with a `grep` or `find` across the relevant kernel source directories if I have access to it, or if it's a closed source, I will need to search the documentation and API references. I will be looking for header files, C files, or makefiles that reference this function. Once I pinpoint the file, I can then use a code editor or IDE with cross-referencing capabilities to find its declaration, implementation, and most importantly, where and how it's used within the driver or related subsystems. The context of its use will give me clues about its purpose - is it part of device uninitialization, resource cleanup, or maybe some kind of analog signal deactivation? My goal is to understand how the system interacts with the device. If it's a kernel function, I'll need to understand the surrounding code to determine how it is implemented and its dependencies. If it's a user-space function, I'll need to check the build process to understand its location and dependencies.
|
| 275/2 |
2026/07/30 13:02 |
tool |
grepper |
0m
Args: map[Expression:au0828_analog_unregister]
Results: map[Output:drivers/media/usb/au0828/au0828-core.c=163=static void au0828_usb_disconnect(struct usb_interface *interface)
--
drivers/media/usb/au0828/au0828-core.c-184- mutex_unlock(&dev->mutex);
drivers/media/usb/au0828/au0828-core.c:185: if (au0828_analog_unregister(dev)) {
drivers/media/usb/au0828/au0828-core.c-186- /*
--
drivers/media/usb/au0828/au0828-video.c=911=static const struct vb2_ops au0828_video_qops = {
--
drivers/media/usb/au0828/au0828-video.c-923-/*
drivers/media/usb/au0828/au0828-video.c:924: * au0828_analog_unregister
drivers/media/usb/au0828/au0828-video.c-925- * unregister v4l2 devices
drivers/media/usb/au0828/au0828-video.c-926- */
drivers/media/usb/au0828/au0828-video.c:927:int au0828_analog_unregister(struct au0828_dev *dev)
drivers/media/usb/au0828/au0828-video.c-928-{
drivers/media/usb/au0828/au0828-video.c:929: dprintk(1, "au0828_analog_unregister called\n");
drivers/media/usb/au0828/au0828-video.c-930-
--
drivers/media/usb/au0828/au0828.h=327=extern int au0828_analog_register(struct au0828_dev *dev,
drivers/media/usb/au0828/au0828.h-328- struct usb_interface *interface);
drivers/media/usb/au0828/au0828.h:329:extern int au0828_analog_unregister(struct au0828_dev *dev);
drivers/media/usb/au0828/au0828.h-330-extern void au0828_usb_v4l2_media_release(struct au0828_dev *dev);
--
drivers/media/usb/au0828/au0828.h=337=static inline int au0828_analog_register(struct au0828_dev *dev,
--
drivers/media/usb/au0828/au0828.h-339-{ return 0; };
drivers/media/usb/au0828/au0828.h:340:static inline int au0828_analog_unregister(struct au0828_dev *dev)
drivers/media/usb/au0828/au0828.h-341-{ return 0; };
]
|
| 276/2 |
2026/07/30 13:02 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 56275
output: 49
thoughts: 15
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Analyzing the `au0828_analog_unregister` Function**
Alright, let's dive into the `au0828_analog_unregister` function. My initial thought is to understand its role within the broader context of the `au0828` driver. It's safe to assume, given the naming, that this function is responsible for cleanly detaching and releasing resources associated with the analog component of the `au0828` device. This is crucial for proper device lifecycle management β preventing memory leaks, dangling pointers, and potential conflicts with other drivers or system components.
I'll be looking for key aspects:
* **Resource Deallocation:** What specific analog resources are being freed? Is it I/O memory mappings, interrupt handlers, DMA channels, or potentially power management contexts? I need to ascertain the level of granularity in its clean up.
* **Driver Unregistration:** How is the analog component unregistered from the larger `au0828` driver structure? Is there a cascading effect, unregistering sub-components as well?
* **Error Handling:** What kind of error checking is implemented? Does it handle situations where resources are already deallocated or where the unregistration fails midway? Are there any return codes or error messages that need attention?
* **Synchronization:** How does it handle potential concurrent access or interrupts during the unregistration process? Are there mutexes, spinlocks, or other synchronization primitives in place to prevent race conditions? I expect there to be a careful locking strategy.
* **Power Management:** Is there any interaction with power management interfaces to put the analog component into a low-power state or shut it down completely? This is critical for battery-powered systems or scenarios where the device can be inactive.
* **Contextual Considerations:** What about the context that this unregistration happens within? Is it always from a user thread, a kernel thread, or an interrupt handler? The context will influence what strategies are possible.
I'll be paying close attention to any dependencies on other functions or data structures within the `au0828` driver. Understanding these relationships is vital to ensure that the unregistration process is complete and doesn't leave the system in an inconsistent state. My aim is to achieve a deep and holistic understanding of its purpose, the risks of using it and the potential failures.
|
| 277/2 |
2026/07/30 13:03 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-video.c FirstLine:920 LineCount:50]
Results: map[Contents: 920: /* ------------------------------------------------------------------
921: V4L2 interface
922: ------------------------------------------------------------------*/
923: /*
924: * au0828_analog_unregister
925: * unregister v4l2 devices
926: */
927: int au0828_analog_unregister(struct au0828_dev *dev)
928: {
929: dprintk(1, "au0828_analog_unregister called\n");
930:
931: /* No analog TV */
932: if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
933: return 0;
934:
935: mutex_lock(&au0828_sysfs_lock);
936: vb2_video_unregister_device(&dev->vdev);
937: vb2_video_unregister_device(&dev->vbi_dev);
938: mutex_unlock(&au0828_sysfs_lock);
939:
940: v4l2_device_disconnect(&dev->v4l2_dev);
941: v4l2_device_put(&dev->v4l2_dev);
942:
943: return 1;
944: }
945:
946: /* This function ensures that video frames continue to be delivered even if
947: the ITU-656 input isn't receiving any data (thereby preventing applications
948: such as tvtime from hanging) */
949: static void au0828_vid_buffer_timeout(struct timer_list *t)
950: {
951: struct au0828_dev *dev = timer_container_of(dev, t, vid_timeout);
952: struct au0828_dmaqueue *dma_q = &dev->vidq;
953: struct au0828_buffer *buf;
954: unsigned char *vid_data;
955: unsigned long flags = 0;
956:
957: spin_lock_irqsave(&dev->slock, flags);
958:
959: buf = dev->isoc_ctl.buf;
960: if (buf != NULL) {
961: vid_data = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
962: memset(vid_data, 0x00, buf->length); /* Blank green frame */
963: buffer_filled(dev, dma_q, buf);
964: }
965: get_next_buf(dma_q, &buf);
966:
967: if (dev->vid_timeout_running == 1)
968: mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
969:
]
|
| 278/2 |
2026/07/30 13:03 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 57704
output: 49
thoughts: 249
Thoughts: **Analyzing the Analog Unregistration and USB Release Logic**
Okay, so I'm looking at this `au0828_usb_disconnect` function and something's bugging me. Specifically, I'm focusing on the interaction between `au0828_analog_unregister` and `au0828_usb_release`. It looks like `au0828_analog_unregister` returns `1` when `AUVI_INPUT(0).type` is *not* `AU0828_VMUX_UNDEFINED`. Now, if that function returns `1`, the entire `au0828_usb_disconnect` function simply returns early. That means the subsequent call to `au0828_usb_release(dev)` is *skipped*. Hmm.
But...wait a minute. I know `au0828_usb_release(dev)` *is* called elsewhere, specifically within `au0828_usb_v4l2_release()` when the last V4L2 device is closed. So, if `au0828_analog_unregister` fails (returns 1) and we return early, we *shouldn't* have an issue. Because the cleanup is handled by V4L2.
I need to confirm this assumption. The key is in understanding how `au0828_usb_v4l2_release` is interacting. I need to make sure my understanding of this control flow is correct. Time to dig into `au0828_usb_v4l2_release`!
|
| 279/2 |
2026/07/30 13:03 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:140 LineCount:50]
Results: map[Contents: 140:
141: /* clear enable_source, disable_source */
142: mutex_lock(&mdev->graph_mutex);
143: dev->media_dev->source_priv = NULL;
144: dev->media_dev->enable_source = NULL;
145: dev->media_dev->disable_source = NULL;
146: mutex_unlock(&mdev->graph_mutex);
147:
148: media_device_delete(dev->media_dev, KBUILD_MODNAME, THIS_MODULE);
149: dev->media_dev = NULL;
150: #endif
151: }
152:
153: void au0828_usb_release(struct au0828_dev *dev)
154: {
155: au0828_unregister_media_device(dev);
156:
157: /* I2C */
158: au0828_i2c_unregister(dev);
159:
160: kfree(dev);
161: }
162:
163: static void au0828_usb_disconnect(struct usb_interface *interface)
164: {
165: struct au0828_dev *dev = usb_get_intfdata(interface);
166:
167: dprintk(1, "%s()\n", __func__);
168:
169: /* there is a small window after disconnect, before
170: dev->usbdev is NULL, for poll (e.g: IR) try to access
171: the device and fill the dmesg with error messages.
172: Set the status so poll routines can check and avoid
173: access after disconnect.
174: */
175: set_bit(DEV_DISCONNECTED, &dev->dev_state);
176:
177: au0828_rc_unregister(dev);
178: /* Digital TV */
179: au0828_dvb_unregister(dev);
180:
181: usb_set_intfdata(interface, NULL);
182: mutex_lock(&dev->mutex);
183: dev->usbdev = NULL;
184: mutex_unlock(&dev->mutex);
185: if (au0828_analog_unregister(dev)) {
186: /*
187: * No need to call au0828_usb_release() if V4L2 is enabled,
188: * as this is already called via au0828_usb_v4l2_release()
189: */
]
|
| 280/2 |
2026/07/30 13:03 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 59127
output: 48
thoughts: 421
Thoughts: **The Eureka Moment!**
Yes! The `au0828_usb_release` function *does* call `au0828_i2c_unregister(dev)`! This is key. And, crucially, `au0828_usb_release` is called when the V4L2 device associated with the USB device is closed. So, if I open the V4L2 device, disconnect the USB device, the I2C adapter *isn't* unregistered! The USB core then goes ahead and frees the USB device. And then, here's the kicker: I can perform an I2C transaction on the I2C adapter, which will attempt to dereference `adapter->dev.parent->type` which is actually `usbdev->type`! Boom! This is *exactly* the bug! The classic use-after-free!
Perfect. This makes the `au0828` driver an ideal target. I need to construct a solid reproducer for this.
Let's see. I need to use `syz_usb_connect`, and the Vendor ID (`idVendor`) must be `0x2040`, and the Product ID (`idProduct`) is `0x7200`. Wait, I need to make sure the `bInterfaceNumber` of the device to be probed is `0`, because `au0828_usb_probe` checks `ifnum != 0`. Then the USB device speed must be `USB_SPEED_HIGH`, which equates to `3`.
Now, let's double-check `au0828_analog_register`. The code verifies that `AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED`. `AUVI_INPUT` uses `dev->board`. And `dev->boardnr` is assigned from `id->driver_info`. Looking at `au0828_usb_id_table`, the combination `0x2040:0x7200` maps to `AU0828_BOARD_HAUPPAUGE_HVR950Q`. Now, let's verify what `au0828_boards[AU0828_BOARD_HAUPPAUGE_HVR950Q]` contains... This is coming together nicely!
|
| 281/2 |
2026/07/30 13:03 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-cards.c FirstLine:40 LineCount:50]
Results: map[Contents: 40: .has_ir_i2c = 1,
41: .has_analog = 1,
42: .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
43: .input = {
44: {
45: .type = AU0828_VMUX_TELEVISION,
46: .vmux = AU8522_COMPOSITE_CH4_SIF,
47: .amux = AU8522_AUDIO_SIF,
48: },
49: {
50: .type = AU0828_VMUX_COMPOSITE,
51: .vmux = AU8522_COMPOSITE_CH1,
52: .amux = AU8522_AUDIO_NONE,
53: .audio_setup = hvr950q_cs5340_audio,
54: },
55: {
56: .type = AU0828_VMUX_SVIDEO,
57: .vmux = AU8522_SVIDEO_CH13,
58: .amux = AU8522_AUDIO_NONE,
59: .audio_setup = hvr950q_cs5340_audio,
60: },
61: },
62: },
63: [AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
64: .name = "Hauppauge HVR950Q",
65: .tuner_type = TUNER_XC5000,
66: .tuner_addr = 0x61,
67: .has_ir_i2c = 1,
68: .has_analog = 1,
69: .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
70: .input = {
71: {
72: .type = AU0828_VMUX_TELEVISION,
73: .vmux = AU8522_COMPOSITE_CH4_SIF,
74: .amux = AU8522_AUDIO_SIF,
75: },
76: {
77: .type = AU0828_VMUX_COMPOSITE,
78: .vmux = AU8522_COMPOSITE_CH1,
79: .amux = AU8522_AUDIO_NONE,
80: .audio_setup = hvr950q_cs5340_audio,
81: },
82: {
83: .type = AU0828_VMUX_SVIDEO,
84: .vmux = AU8522_SVIDEO_CH13,
85: .amux = AU8522_AUDIO_NONE,
86: .audio_setup = hvr950q_cs5340_audio,
87: },
88: },
89: },
]
|
| 282/2 |
2026/07/30 13:03 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 60968
output: 35
thoughts: 808
Thoughts: **Analyzing the USB Device Driver Probe**
Okay, so I'm looking at this probe function and the first thing I see is that `input[0].type` is definitely the right kind of television device. Great, so far so good. It looks like the driver then calls `au0828_analog_register`, which is where things get interesting. It's trying to set the USB interface 0 to alternate setting 5. If the USB interface doesn't *have* alternate setting 5, this `usb_set_interface` will fail and the entire `au0828_analog_register` will return an error, which in turn means the probe function, `au0828_usb_probe`, will fail! The failure will jump to a cleanup routine that disconnects the device and returns the error code. The device will *not* be registered.
So, I absolutely MUST ensure that alternate setting 5 exists for interface 0. The key is the `usb_interface_descriptor` and its `bAlternateSetting` field. I need to provide multiple of these descriptors for the same `bInterfaceNumber` (0), covering alternate settings from 0 through 5.
Now, let's see how I can do that using syzkaller. I see the `usb_config_descriptor_verbose_t` struct, and it has an `interfaces` field, which is an array of `usb_interface_descriptor`, but the documentation seems to limit it to 1-4. That's a problem! I need 6 alternate settings, but I only have the ability to supply 4 interface descriptors according to the documentation.
Wait, the `usb_interface_descriptor` actually *represents* an alternate setting! It's not a general interface description. So I can provide 6 `usb_interface_descriptor`s for interface 0, each with a different `bAlternateSetting` value.
However, the syzkaller limitation remains. The struct `usb_config_descriptor_ifaces_array_t` limits the number of interface descriptors. Hmmm, the `ANY` keyword might bypass this array size limit. Wait! I can also just use `syz_usb_connect` with `ANY`.
But then, `syz_usb_connect` takes `dev ptr[in, usb_device_descriptor]`. If I just pass a byte array, it will say "wrong struct arg".
But wait! `syz_usb_connect` has a special video version too, `syz_usb_connect$video`! It takes a `usb_device_descriptor_video` structure. Does that one have a way to specify alternate settings? Let me check the documentation ("vusb.txt") for the `usb_device_descriptor_video`...
|
| 283/2 |
2026/07/30 13:03 |
tool |
read-file |
0m
Error:
Args: map[File:sys/linux/vusb.txt FirstLine:1 LineCount:100]
Results:
|
| 284/2 |
2026/07/30 13:03 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 62426
output: 37
thoughts: 17
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Analyzing the `sys/linux/dev_vusb.txt` Context**
Okay, here we go. The filename, `sys/linux/dev_vusb.txt`, immediately pegs this as a potentially crucial piece of documentation or configuration related to USB virtual devices within a Linux kernel environment. The "sys" prefix suggests a kernel-level configuration or device information file, so I'm already thinking about device nodes, sysfs entries, or even kernel command-line parameters that influence virtual USB device behavior. The "dev" part is obviously about devices, and "vusb" screams "virtual USB," which implies emulated USB devices, likely used for testing, virtualization, or maybe even advanced embedded systems with USB gadget capabilities. My mind's now running through potential scenarios: Is this about the `g_cdc` driver, a custom virtual USB Ethernet device, or something completely custom? Iβm immediately trying to assess the likely age of the information. "vusb" has been around a while; I'm betting on a moderately recent version of the kernel. Iβm prepared for a deeper dive and I'm ready to figure out the use case.
|
| 285/2 |
2026/07/30 13:03 |
tool |
read-file |
0m
Error:
Args: map[File:sys/linux/dev_vusb.txt FirstLine:1 LineCount:100]
Results:
|
| 286/2 |
2026/07/30 13:03 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 62758
output: 19
thoughts: 12
Thoughts: Okay, here's my attempt at summarizing the thought process, as if it were my own, assuming I'm an expert in the field:
**Eureka! A Tool for This Task**
Right, let me think this through. I'm dealing with a textual task, a description to be read and understood. There has to be a way to avoid manually analyzing this text. Wait a minute... of course! I can use a tool I developed. This situation calls for the `read-description` tool! That's perfect. This is ideal; Itβll handle this task flawlessly. I can use my specialized tool to simplify this task.
|
| 287/2 |
2026/07/30 13:03 |
tool |
read-description |
0m
Args:
Results: map[Output:# Copyright 2019 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
include <linux/types.h>
include <linux/byteorder/generic.h>
include <uapi/linux/usb/ch9.h>
include <uapi/linux/usb/ch11.h>
include <uapi/linux/usb/midi.h>
include <uapi/linux/usb/audio.h>
include <linux/usb/audio-v2.h>
include <linux/usb/audio-v3.h>
include <uapi/linux/hid.h>
include <linux/hid.h>
include <uapi/linux/usb/cdc.h>
include <uapi/linux/if_ether.h>
include <linux/interrupt.h>
include <linux/usb/cdc_ncm.h>
include <drivers/net/usb/asix.h>
# This is a special fd for USB fuzzing and should only be used with syz_usb_* pseudo-syscalls.
# We don't inherit it from the fd resource, to discourage syzkaller calling raw ioctls on it.
resource fd_usb[int32]: -1
# These are generic pseudo-syscalls for emulating arbitrary USB devices.
# They are mostly targeted to cover the enumeration process.
syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io(fd fd_usb, descs ptr[in, vusb_descriptors], resps ptr[in, vusb_responses]) (timeout[300], remote_cover)
syz_usb_ep_write(fd fd_usb, ep int8, len len[data], data ptr[in, array[int8, 0:256]]) (timeout[300], remote_cover)
syz_usb_ep_read(fd fd_usb, ep int8, len len[data], data buffer[out]) (timeout[300], remote_cover)
syz_usb_disconnect(fd fd_usb) (timeout[300], remote_cover)
usb_device_speed = USB_SPEED_UNKNOWN, USB_SPEED_LOW, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_WIRELESS, USB_SPEED_SUPER, USB_SPEED_SUPER_PLUS
# TODO: consider patching idVendor and idProduct for all class specific descriptions in Go code to cover more drivers.
# TODO: custom syz_usb_ep_write() descriptions for all class specific descriptions.
# TODO: consider adding custom vusb_connect_descriptors definitions to all class specific descriptions.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
type usb_device_descriptor_verbose_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] {
bLength const[USB_DT_DEVICE_SIZE, int8]
bDescriptorType const[USB_DT_DEVICE, int8]
bcdUSB USB
bDeviceClass const[CLASS, int8]
bDeviceSubClass const[SUBCLASS, int8]
bDeviceProtocol const[PROTOCOL, int8]
bMaxPacketSize0 PACKET
idVendor const[VENDOR, int16]
idProduct const[PRODUCT, int16]
bcdDevice const[DEVICE, int16]
iManufacturer const[1, int8]
iProduct const[2, int8]
iSerialNumber const[3, int8]
bNumConfigurations len[configs, int8]
configs CFS
} [packed]
type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[flags[usb_versions, int16], CLASS, SUBCLASS, PROTOCOL, flags[usb_device_max_packet_sizes, int8], VENDOR, PRODUCT, DEVICE, CFS]
type usb_device_descriptor_fixed_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[const[USB, int16], CLASS, SUBCLASS, PROTOCOL, const[PACKET, int8], VENDOR, PRODUCT, DEVICE, CFS]
usb_versions = 0x110, 0x200, 0x201, 0x250, 0x300, 0x310
# https://elixir.bootlin.com/linux/v5.1.7/source/drivers/usb/core/hub.c#L4661
usb_device_max_packet_sizes = 8, 16, 32, 64, 255
type usb_config_descriptor_verbose_t[NUM, IFSNUM, ICONFIG, ATTRS, POWER, EXTRA, IFS] {
bLength const[USB_DT_CONFIG_SIZE, int8]
bDescriptorType const[USB_DT_CONFIG, int8]
wTotalLength len[parent, int16]
bNumInterfaces IFSNUM
bConfigurationValue NUM
iConfiguration ICONFIG
bmAttributes ATTRS
bMaxPower POWER
extra EXTRA
interfaces IFS
} [packed]
type usb_config_descriptor_t[NUM, IFSNUM, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, void, IFS]
type usb_config_descriptor_ifaces_array_t[NUM, IFS] usb_config_descriptor_t[NUM, len[interfaces, int8], IFS]
type usb_config_descriptor_fixed_t[NUM, IFSNUM, ATTRS, POWER, IFS] usb_config_descriptor_verbose_t[const[NUM, int8], const[IFSNUM, int8], const[0, int8], const[ATTRS, int8], const[POWER, int8], void, IFS]
type usb_config_descriptor_extra_t[NUM, IFSNUM, EXTRA, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, EXTRA, IFS]
type usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, IIF, EXTRA, EPS] {
bLength const[USB_DT_INTERFACE_SIZE, int8]
bDescriptorType const[USB_DT_INTERFACE, int8]
bInterfaceNumber IFNUM
bAlternateSetting ALTNUM
bNumEndpoints EPSNUM
bInterfaceClass CLASS
bInterfaceSubClass SUBCLASS
bInterfaceProtocol PROTOCOL
iInterface IIF
extra EXTRA
endpoints EPS
} [packed]
type usb_interface_descriptor_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, int8, EXTRA, EPS]
type usb_interface_descriptor_eps_array_t[IFNUM, ALTNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_t[IFNUM, ALTNUM, len[endpoints, int8], CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS]
type usb_interface_descriptor_fixed_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[const[IFNUM, int8], const[ALTNUM, int8], const[EPSNUM, int8], const[CLASS, int8], const[SUBCLASS, int8], const[PROTOCOL, int8], const[0, int8], EXTRA, EPS]
# TODO: non-audio endpoints have USB_DT_ENDPOINT_SIZE.
type usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, PACKET, INTERVAL, REFRESH, SYNCH, EXTRA] {
bLength const[USB_DT_ENDPOINT_AUDIO_SIZE, int8]
bDescriptorType const[USB_DT_ENDPOINT, int8]
bEndpointAddress ADDR
bmAttributes ATTRS
wMaxPacketSize PACKET
bInterval INTERVAL
bRefresh REFRESH
bSynchAddress SYNCH
extra EXTRA
} [packed]
type usb_endpoint_descriptor_t[ADDR, ATTRS, EXTRA] usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, EXTRA]
type usb_endpoint_descriptor_fixed_t[ADDR, ATTRS, PACKET, INTERVAL, EXTRA] usb_endpoint_descriptor_verbose_t[const[ADDR, int8], const[ATTRS, int8], const[PACKET, int16], const[INTERVAL, int8], const[0, int8], const[0, int8], EXTRA]
# TODO: dummy driver has complex requirements for packet sizes, account for those:
# https://elixir.bootlin.com/linux/v5.3.6/source/drivers/usb/gadget/udc/dummy_hcd.c#L497
usb_endpoint_max_packet_sizes = 8, 16, 32, 64, 512, 1023, 1024
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Generic USB device, configuration, interface and endpoint descriptors.
# We only support one configuration per device.
# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct
# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]]
} [packed]
usb_config_descriptor {
inner usb_config_descriptor_ifaces_array_t[int8, array[usb_interface_descriptor, 1:4]]
} [packed]
usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY
# bInterfaceNumber, bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol
# are patched by Go code, see sys/linux/init_vusb.go.
usb_interface_descriptor {
inner usb_interface_descriptor_eps_array_t[int8, int8, const[0, int8], const[0, int8], const[0, int8], array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
} [packed]
usb_endpoint_descriptor {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], array[usb_endpoint_extra_descriptor, 0:2]]
} [packed]
usb_endpoint_addresses = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, USB_DIR_OUT, USB_DIR_IN
usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK
vusb_connect_descriptors {
qual_len len[qual, int32]
qual ptr[in, usb_qualifier_descriptor]
bos_len len[bos, int32]
bos ptr[in, usb_bos_descriptor]
strs_len len[strs, int32]
strs array[vusb_connect_string_descriptor]
} [packed]
vusb_connect_string_descriptor {
len len[str, int32]
str ptr[in, usb_string_descriptor]
} [packed]
vusb_descriptors {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]]
hub_hs ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_HUB, usb_hub_descriptor_hs]]
hub_ss ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_SS_HUB, usb_hub_descriptor_ss]]
} [packed]
vusb_descriptor_generic {
req_type flags[usb_request_types, int8]
desc_type flags[usb_descriptor_types, int8]
len bytesize[data, int32]
data usb_generic_descriptor
} [packed]
usb_request_types = USB_TYPE_STANDARD, USB_TYPE_CLASS, USB_TYPE_VENDOR
type vusb_descriptor_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# TODO: consider doing lookups based on USB_RECIP values.
vusb_responses {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
get_interface ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
get_configuration ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
# TODO: move these into custom descriptions for hub class when they are added.
hub_USB_REQ_GET_STATUS_hub ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_hub_status]]
hub_USB_REQ_GET_STATUS_port ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_port_status]]
# TODO: move these into custom descriptions for asix driver when they are added.
asix_AX_CMD_READ_MII_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MII_REG, int16]]
asix_AX_CMD_STATMNGSTS_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_STATMNGSTS_REG, int8]]
asix_AX_CMD_READ_EEPROM ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_EEPROM, array[int8, 2]]]
asix_AX_CMD_READ_RX_CTL ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_RX_CTL, int16]]
asix_AX_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_NODE_ID, mac_addr]]
asix_AX88172_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX88172_CMD_READ_NODE_ID, mac_addr]]
asix_AX_CMD_READ_PHY_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_PHY_ID, array[int8, 2]]]
asix_AX_CMD_READ_MEDIUM_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MEDIUM_STATUS, int16]]
asix_AX_CMD_READ_MONITOR_MODE ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MONITOR_MODE, int8]]
asix_AX_CMD_READ_GPIOS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_GPIOS, int8]]
asix_AX_CMD_SW_PHY_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_SW_PHY_STATUS, int8]]
} [packed]
vusb_response_generic {
type flags[usb_request_types, int8]
req flags[usb_requests, int8]
len bytesize[data, int32]
data array[int8, 0:256]
} [packed]
usb_requests = USB_REQ_GET_STATUS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, USB_REQ_SET_ADDRESS, USB_REQ_GET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR, USB_REQ_GET_CONFIGURATION, USB_REQ_SET_CONFIGURATION, USB_REQ_GET_INTERFACE, USB_REQ_SET_INTERFACE, USB_REQ_SYNCH_FRAME, USB_REQ_SET_SEL, USB_REQ_SET_ISOCH_DELAY, USB_REQ_SET_ENCRYPTION, USB_REQ_GET_ENCRYPTION, USB_REQ_RPIPE_ABORT, USB_REQ_SET_HANDSHAKE, USB_REQ_RPIPE_RESET, USB_REQ_GET_HANDSHAKE, USB_REQ_SET_CONNECTION, USB_REQ_SET_SECURITY_DATA, USB_REQ_GET_SECURITY_DATA, USB_REQ_SET_WUSB_DATA, USB_REQ_LOOPBACK_DATA_WRITE, USB_REQ_LOOPBACK_DATA_READ, USB_REQ_SET_INTERFACE_DS, USB_REQ_GET_PARTNER_PDO, USB_REQ_GET_BATTERY_STATUS, USB_REQ_SET_PDO, USB_REQ_GET_VDM, USB_REQ_SEND_VDM
type vusb_response_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested by the kernel before the SET_CONFIGURATION request.
# TODO: figure out when is the USB_DT_OTG descriptor used.
# TODO: figure out when is the USB_DT_INTERFACE_ASSOCIATION descriptor used.
# TODO: figure out when is the USB_DT_BOS descriptor used.
type usb_string_descriptor_t[DATA] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_STRING, int8]
data DATA
} [packed]
usb_string_descriptor [
lang_id usb_string_descriptor_t[flags[usb_lang_ids, int16]]
string usb_string_descriptor_t[array[int8, 0:256]]
] [varlen]
usb_lang_ids = 0x436, 0x41c, 0x401, 0x801, 0xc01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001, 0x42b, 0x44d, 0x42c, 0x82c, 0x42d, 0x423, 0x445, 0x402, 0x455, 0x403, 0x404, 0x804, 0xc04, 0x1004, 0x1404, 0x41a, 0x405, 0x406, 0x413, 0x813, 0x409, 0x809, 0xc09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x425, 0x438, 0x429, 0x40b, 0x40c, 0x80c, 0xc0c, 0x100c, 0x140c, 0x180c, 0x437, 0x407, 0x807, 0xc07, 0x1007, 0x1407, 0x408, 0x447, 0x40d, 0x439, 0x40e, 0x40f, 0x421, 0x410, 0x810, 0x411, 0x44b, 0x860, 0x43f, 0x457, 0x412, 0x812, 0x426, 0x427, 0x827, 0x42f, 0x43e, 0x83e, 0x44c, 0x458, 0x44e, 0x861, 0x414, 0x814, 0x448, 0x415, 0x416, 0x816, 0x446, 0x418, 0x419, 0x44f, 0xc1a, 0x81a, 0x459, 0x41b, 0x424, 0x40a, 0x80a, 0xc0a, 0x100a, 0x140a, 0x180a, 0x1c0a, 0x200a, 0x240a, 0x280a, 0x2c0a, 0x300a, 0x340a, 0x380a, 0x3c0a, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a, 0x430, 0x441, 0x41d, 0x81d, 0x449, 0x444, 0x44a, 0x41e, 0x41f, 0x422, 0x420, 0x820, 0x443, 0x843, 0x42a, 0x4ff, 0xf0ff, 0xf4ff, 0xf8ff, 0xfcff
usb_qualifier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_QUALIFIER, int8]
bcdUSB flags[usb_versions, int16]
bDeviceClass int8
bDeviceSubClass int8
bDeviceProtocol int8
bMaxPacketSize0 flags[usb_device_max_packet_sizes, int8]
bNumConfigurations int8
bRESERVED const[0, int8]
} [packed]
usb_bos_descriptor {
bLength const[USB_DT_BOS_SIZE, int8]
bDescriptorType const[USB_DT_BOS, int8]
wTotalLength len[parent, int16]
bNumDeviceCaps len[caps, int8]
caps array[usb_dev_cap, 0:6]
} [packed]
usb_dev_cap [
generic usb_generic_cap_descriptor
wireless usb_wireless_cap_descriptor
ext_cap usb_ext_cap_descriptor
ss_cap usb_ss_cap_descriptor
ss_container_id usb_ss_container_id_descriptor
ssp_cap usb_ssp_cap_descriptor
ptm_cap usb_ptm_cap_descriptor
] [varlen]
usb_generic_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType flags[usb_capability_types, int8]
data array[int8, 0:256]
} [packed]
usb_capability_types = USB_CAP_TYPE_WIRELESS_USB, USB_CAP_TYPE_EXT, USB_SS_CAP_TYPE, USB_SSP_CAP_TYPE, CONTAINER_ID_TYPE, USB_PTM_CAP_TYPE
usb_wireless_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_WIRELESS_USB, int8]
bmAttributes flags[usb_wireless_cap_attributes, int8]
wPHYRates flags[usb_wireless_cap_phyrates, int16]
bmTFITXPowerInfo int8
bmFFITXPowerInfo int8
bmBandGroup int16
bReserved int8
} [packed]
usb_wireless_cap_attributes = USB_WIRELESS_P2P_DRD, USB_WIRELESS_BEACON_MASK, USB_WIRELESS_BEACON_SELF, USB_WIRELESS_BEACON_DIRECTED, USB_WIRELESS_BEACON_NONE
usb_wireless_cap_phyrates = USB_WIRELESS_PHY_53, USB_WIRELESS_PHY_80, USB_WIRELESS_PHY_107, USB_WIRELESS_PHY_160, USB_WIRELESS_PHY_200, USB_WIRELESS_PHY_320, USB_WIRELESS_PHY_400, USB_WIRELESS_PHY_480
usb_ext_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_EXT, int8]
bmAttributes1 flags[usb_ext_cap_attributes, int32:8]
bmAttributes2 int32:4
bmAttributes3 int32:4
bmAttributes4 int32:16
} [packed]
usb_ext_cap_attributes = USB_LPM_SUPPORT, USB_BESL_SUPPORT, USB_BESL_BASELINE_VALID, USB_BESL_DEEP_VALID
usb_ss_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SS_CAP_TYPE, int8]
bmAttributes flags[usb_ss_cap_attributes, int8]
wSpeedSupported flags[usb_ss_cap_speed, int16]
bFunctionalitySupport int8
bU1devExitLat int8
bU2DevExitLat int16
} [packed]
usb_ss_cap_attributes = USB_LTM_SUPPORT
usb_ss_cap_speed = USB_LOW_SPEED_OPERATION, USB_FULL_SPEED_OPERATION, USB_HIGH_SPEED_OPERATION, USB_5GBPS_OPERATION
usb_ss_container_id_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[CONTAINER_ID_TYPE, int8]
bReserved int8
ContainerID array[int8, 16]
} [packed]
usb_ssp_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SSP_CAP_TYPE, int8]
bReserved int8
bmAttributesSublinkSpeeds len[bmSublinkSpeedAttr, int32:5]
bmAttributesSpeedIDs int32:27
wFunctionalitySupport flags[usb_ssp_cap_funcs, int16]
wReserved int16
bmSublinkSpeedAttr array[flags[usb_ssp_cap_sublink_speeds, int32], 0:6]
} [packed]
usb_ssp_cap_funcs = USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, USB_SSP_MIN_RX_LANE_COUNT, USB_SSP_MIN_TX_LANE_COUNT
usb_ssp_cap_sublink_speeds = USB_SSP_SUBLINK_SPEED_SSID, USB_SSP_SUBLINK_SPEED_LSE, USB_SSP_SUBLINK_SPEED_ST, USB_SSP_SUBLINK_SPEED_RSVD, USB_SSP_SUBLINK_SPEED_LP, USB_SSP_SUBLINK_SPEED_LSM
usb_ptm_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_PTM_CAP_TYPE, int8]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Extra USB descriptors that come after an interface or an endpoint descriptor.
# TODO: consider removing class specific descriptors here for described classes.
usb_interface_extra_descriptor [
generic usb_generic_descriptor
hid_hid usb_hid_descriptor_hid
cdc_ecm usb_cdc_header_ecm
cdc_ncm usb_cdc_header_ncm
uac_control uac_control_iface_extra_descriptors
uac_as uac_as_iface_extra_descriptors
] [varlen]
usb_endpoint_extra_descriptor [
generic usb_generic_descriptor
uac_iso uac_iso_endpoint_descriptor
] [varlen]
usb_generic_descriptor {
bLength len[parent, int8]
bDescriptorType flags[usb_descriptor_types, int8]
data array[int8, 0:256]
} [packed]
usb_descriptor_types = USB_DT_DEVICE, USB_DT_CONFIG, USB_DT_STRING, USB_DT_INTERFACE, USB_DT_ENDPOINT, USB_DT_DEVICE_QUALIFIER, USB_DT_OTHER_SPEED_CONFIG, USB_DT_INTERFACE_POWER, USB_DT_OTG, USB_DT_DEBUG, USB_DT_INTERFACE_ASSOCIATION, USB_DT_SECURITY, USB_DT_KEY, USB_DT_ENCRYPTION_TYPE, USB_DT_BOS, USB_DT_DEVICE_CAPABILITY, USB_DT_WIRELESS_ENDPOINT_COMP, USB_DT_WIRE_ADAPTER, USB_DT_RPIPE, USB_DT_CS_RADIO_CONTROL, USB_DT_PIPE_USAGE, USB_DT_SS_ENDPOINT_COMP, USB_DT_SSP_ISOC_ENDPOINT_COMP, HID_DT_HID, HID_DT_REPORT, HID_DT_PHYSICAL
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested after the SET_CONFIGURATION request.
usb_hub_descriptor_hs {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
DeviceRemovable array[int8, USB_HUB_PORTS_BITS]
PortPwrCtrlMask array[int8, USB_HUB_PORTS_BITS]
} [packed]
usb_hub_descriptor_ss {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_SS_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
bHubHdrDecLat int8
wHubDelay int16
DeviceRemovable int16
} [packed]
define USB_HUB_PORTS_BITS ((USB_MAXCHILDREN + 1 + 7) / 8)
usb_hub_characteristics = HUB_CHAR_LPSM, HUB_CHAR_COMMON_LPSM, HUB_CHAR_INDV_PORT_LPSM, HUB_CHAR_NO_LPSM, HUB_CHAR_COMPOUND, HUB_CHAR_OCPM, HUB_CHAR_COMMON_OCPM, HUB_CHAR_INDV_PORT_OCPM, HUB_CHAR_NO_OCPM, HUB_CHAR_TTTT, HUB_CHAR_PORTIND
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Replies to USB control requests requested after the SET_CONFIGURATION request.
usb_port_status {
wPortStatus flags[usb_port_status_flags, int16]
wPortChange flags[usb_port_change_flags, int16]
dwExtPortStatus array[flags[usb_ext_port_status_flags, int32], 0:1]
} [packed]
usb_port_status_flags = USB_PORT_STAT_CONNECTION, USB_PORT_STAT_ENABLE, USB_PORT_STAT_SUSPEND, USB_PORT_STAT_OVERCURRENT, USB_PORT_STAT_RESET, USB_PORT_STAT_L1, USB_PORT_STAT_POWER, USB_PORT_STAT_LOW_SPEED, USB_PORT_STAT_HIGH_SPEED, USB_PORT_STAT_TEST, USB_PORT_STAT_INDICATOR, USB_PORT_STAT_LINK_STATE, USB_SS_PORT_STAT_POWER, USB_SS_PORT_STAT_SPEED, USB_PORT_STAT_SPEED_5GBPS, USB_SS_PORT_LS_U0, USB_SS_PORT_LS_U1, USB_SS_PORT_LS_U2, USB_SS_PORT_LS_U3, USB_SS_PORT_LS_SS_DISABLED, USB_SS_PORT_LS_RX_DETECT, USB_SS_PORT_LS_SS_INACTIVE, USB_SS_PORT_LS_POLLING, USB_SS_PORT_LS_RECOVERY, USB_SS_PORT_LS_HOT_RESET, USB_SS_PORT_LS_COMP_MOD, USB_SS_PORT_LS_LOOPBACK
usb_port_change_flags = USB_PORT_STAT_C_CONNECTION, USB_PORT_STAT_C_ENABLE, USB_PORT_STAT_C_SUSPEND, USB_PORT_STAT_C_OVERCURRENT, USB_PORT_STAT_C_RESET, USB_PORT_STAT_C_L1, USB_PORT_STAT_C_BH_RESET, USB_PORT_STAT_C_LINK_STATE, USB_PORT_STAT_C_CONFIG_ERROR
usb_ext_port_status_flags = USB_EXT_PORT_STAT_RX_SPEED_ID, USB_EXT_PORT_STAT_TX_SPEED_ID, USB_EXT_PORT_STAT_RX_LANES, USB_EXT_PORT_STAT_TX_LANES
usb_hub_status {
wHubStatus flags[usb_hub_status_flags, int16]
wHubChange flags[usb_hub_change_flags, int16]
} [packed]
usb_hub_status_flags = HUB_STATUS_LOCAL_POWER, HUB_STATUS_OVERCURRENT
usb_hub_change_flags = HUB_CHANGE_LOCAL_POWER, HUB_CHANGE_OVERCURRENT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# HID device class specific descriptions.
# https://www.usb.org/sites/default/files/documents/hid1_11.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/usbhid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/hid.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_hid.c
# Connected HID devices are known to create the following /dev/ files:
# /dev/hidraw#, /dev/usb/hiddev# and /dev/input/event#.
resource fd_usb_hid[fd_usb]
syz_usb_connect$hid(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_hid], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_hid (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$hid(fd fd_usb_hid, descs ptr[in, vusb_descriptors_hid], resps ptr[in, vusb_responses_hid]) (timeout[300], remote_cover)
# idVendor and idProduct are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor_hid {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 64, array[usb_config_descriptor_hid, 1]]
} [packed]
usb_config_descriptor_hid {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_hid, 1]]
} [packed]
usb_interface_descriptor_hid {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_HID, int8], const[USB_INTERFACE_SUBCLASS_BOOT, int8], flags[usb_hid_protocols, int8], usb_hid_descriptor_hid, usb_endpoint_descriptors_hid]
} [packed]
usb_hid_protocols = USB_INTERFACE_PROTOCOL_KEYBOARD, USB_INTERFACE_PROTOCOL_MOUSE
usb_endpoint_descriptors_hid {
in usb_endpoint_descriptor_hid_in
out array[usb_endpoint_descriptor_hid_out, 0:1]
} [packed]
usb_endpoint_descriptor_hid_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_IN_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_hid_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_OUT_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_HID_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_HID_IN_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_HID_OUT_ADDRESS (2)
vusb_descriptors_hid {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
# For unknown reasons these are requested as USB_TYPE_STANDARD and not as USB_TYPE_CLASS.
# Linux doesn't request HID_DT_HID, but some hosts might do that.
HID_DT_REPORT ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]]
HID_DT_HID ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_HID, usb_hid_descriptor_hid]]
} [packed]
vusb_responses_hid {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
HID_REQ_GET_REPORT ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_REPORT, array[int8, 0:256]]]
HID_REQ_GET_PROTOCOL ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_PROTOCOL, int8]]
} [packed]
# USB HID specifications allows for multiple report and physical descriptors
# to be present, but I don't see any support for them in the Linux kernel,
# except for a single report descriptor.
usb_hid_descriptor_hid {
bLength len[parent, int8]
bDescriptorType const[HID_DT_HID, int8]
bcdHID int16
bCountryCode int8
bNumDescriptors const[1, int8]
report_desc usb_hid_class_descriptor_report
} [packed]
usb_hid_class_descriptor_report {
bDescriptorType const[HID_DT_REPORT, int8]
wDescriptorLength int16[0:HID_MAX_DESCRIPTOR_SIZE]
} [packed]
# TODO: it's hard to describe the REPORT descriptor structure via syzkaller
# descriptions, so consider generating it in Go code.
# TODO: the length of REPORT descriptor must match the value in HID descriptor.
# TODO: there are vendor specific REPORT descriptor formats (Logitech HID++).
# Linux HID stack doesn't support long items.
hid_descriptor_report {
items array[hid_report_item_short]
} [packed]
type hid_report_item_short_012_t[TYPE, TAGS] {
bSize len[data, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 0:2]
} [packed]
type hid_report_item_short_4_t[TYPE, TAGS] {
bSize const[3, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 4]
} [packed]
type hid_report_item_short_t[TYPE, TAGS] [
item_012 hid_report_item_short_012_t[TYPE, TAGS]
item_4 hid_report_item_short_4_t[TYPE, TAGS]
] [varlen]
hid_report_item_short [
main hid_report_item_short_t[HID_ITEM_TYPE_MAIN, hid_report_item_main_tags]
global hid_report_item_short_t[HID_ITEM_TYPE_GLOBAL, hid_report_item_global_tags]
local hid_report_item_short_t[HID_ITEM_TYPE_LOCAL, hid_report_item_local_tags]
] [varlen]
hid_report_item_main_tags = HID_MAIN_ITEM_TAG_INPUT, HID_MAIN_ITEM_TAG_OUTPUT, HID_MAIN_ITEM_TAG_FEATURE, HID_MAIN_ITEM_TAG_BEGIN_COLLECTION, HID_MAIN_ITEM_TAG_END_COLLECTION
hid_report_item_global_tags = HID_GLOBAL_ITEM_TAG_USAGE_PAGE, HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT, HID_GLOBAL_ITEM_TAG_UNIT, HID_GLOBAL_ITEM_TAG_REPORT_SIZE, HID_GLOBAL_ITEM_TAG_REPORT_ID, HID_GLOBAL_ITEM_TAG_REPORT_COUNT, HID_GLOBAL_ITEM_TAG_PUSH, HID_GLOBAL_ITEM_TAG_POP
hid_report_item_local_tags = HID_LOCAL_ITEM_TAG_USAGE, HID_LOCAL_ITEM_TAG_USAGE_MINIMUM, HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX, HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM, HID_LOCAL_ITEM_TAG_STRING_INDEX, HID_LOCAL_ITEM_TAG_STRING_MINIMUM, HID_LOCAL_ITEM_TAG_STRING_MAXIMUM, HID_LOCAL_ITEM_TAG_DELIMITER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# PRINTER device class specific descriptions.
# https://www.usb.org/sites/default/files/usbprint11a021811.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/class/usblp.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/printer.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_printer.c
# Connected PRINTER devices are known to create the following /dev/ files:
# /dev/usb/lp#.
# TODO: write descriptions for those.
# drivers/usb/class/usblp.c
define USBLP_REQ_GET_ID 0x00
define USBLP_REQ_GET_STATUS 0x01
define USBLP_REQ_RESET 0x02
define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00
define USBLP_FIRST_PROTOCOL 1
define USBLP_LAST_PROTOCOL 3
resource fd_usb_printer[fd_usb]
syz_usb_connect$printer(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_printer], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_printer (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$printer(fd fd_usb_printer, descs ptr[in, vusb_descriptors_printer], resps ptr[in, vusb_responses_printer]) (timeout[300], remote_cover)
usb_device_descriptor_printer {
inner usb_device_descriptor_t[0, 0, 0, 0x525, 0xa4a8, 64, array[usb_config_descriptor_printer, 1]]
} [packed]
usb_config_descriptor_printer {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_printer, 1]]
} [packed]
usb_interface_descriptor_printer {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_PRINTER, int8], const[1, int8], int8[USBLP_FIRST_PROTOCOL:USBLP_LAST_PROTOCOL], void, usb_endpoint_descriptors_printer]
} [packed]
usb_endpoint_descriptors_printer {
in usb_endpoint_descriptor_printer_out
out array[usb_endpoint_descriptor_printer_in, 0:1]
} [packed]
usb_endpoint_descriptor_printer_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_OUT_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_printer_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_IN_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_PRINTER_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_PRINTER_OUT_ADDRESS (1)
define USB_ENDPOINT_PRINTER_IN_ADDRESS (2 | USB_DIR_IN)
vusb_descriptors_printer {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_printer {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USBLP_REQ_GET_ID ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_ID, usb_printer_get_id_response]]
USBLP_REQ_GET_STATUS ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_STATUS, int8]]
USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, int8]]
} [packed]
usb_printer_get_id_response {
length len[id, int16be]
id array[int8, 0:256]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC ECM (Ethernet) device class specific descriptions.
# https://www.usb.org/document-library/class-definitions-communication-devices-12
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ecm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/u_ether.c
# Connected CDC ECM devices are known to create usbN network interfaces.
# TODO: write descriptions for those.
resource fd_usb_cdc_ecm[fd_usb]
syz_usb_connect$cdc_ecm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ecm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ecm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ecm(fd fd_usb_cdc_ecm, descs ptr[in, vusb_descriptors_cdc_ecm], resps ptr[in, vusb_responses_cdc_ecm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ecm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ecm, 1]]
} [packed]
usb_config_descriptor_cdc_ecm {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_cdc_ecm, 1]]
} [packed]
# Per specification CDC ECM devices have two interfaces (control and data),
# but here we're merging them into one for simplicity since Linux supports that.
usb_interface_descriptor_cdc_ecm {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[2:3], const[USB_CLASS_COMM, int8], const[USB_CDC_SUBCLASS_ETHERNET, int8], const[USB_CDC_PROTO_NONE, int8], usb_cdc_header_ecm, usb_endpoint_descriptors_cdc_ecm]
} [packed]
usb_endpoint_descriptors_cdc_ecm {
notify array[usb_endpoint_descriptor_cdc_ecm_notify, 0:1]
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
usb_endpoint_descriptor_cdc_ecm_notify {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_IN_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_OUT_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_OUT_ADDRESS (3)
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L155
usb_cdc_header_ecm {
union usb_cdc_union_desc_t[0, 0]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
other array[usb_cdc_header_ecm_other, 0:6]
} [packed]
usb_cdc_header_ecm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
ncm usb_cdc_ncm_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
usb_cdc_header_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_HEADER_TYPE, int8]
bcdCDC int16
} [packed]
usb_cdc_call_mgmt_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_CALL_MANAGEMENT_TYPE, int8]
bmCapabilities flags[usb_cdc_call_mgmt_caps, int8]
bDataInterface int8
} [packed]
usb_cdc_call_mgmt_caps = USB_CDC_CALL_MGMT_CAP_CALL_MGMT, USB_CDC_CALL_MGMT_CAP_DATA_INTF
usb_cdc_acm_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ACM_TYPE, int8]
bmCapabilities flags[usb_cdc_acm_caps, int8]
} [packed]
usb_cdc_acm_caps = USB_CDC_COMM_FEATURE, USB_CDC_CAP_LINE, USB_CDC_CAP_BRK, USB_CDC_CAP_NOTIFY
type usb_cdc_union_desc_t[MASTER, SLAVE] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_UNION_TYPE, int8]
bMasterInterface0 const[MASTER, int8]
bSlaveInterface0 const[SLAVE, int8]
slave_interfaces array[int8, 0:6]
} [packed]
usb_cdc_country_functional_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_COUNTRY_TYPE, int8]
iCountryCodeRelDate int8
wCountyCode0 int16
country_codes array[int16, 0:6]
} [packed]
usb_cdc_network_terminal_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NETWORK_TERMINAL_TYPE, int8]
bEntityId int8
iName int8
bChannelIndex int8
bPhysicalInterface int8
} [packed]
usb_cdc_ether_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ETHERNET_TYPE, int8]
iMACAddress const[1, int8]
bmEthernetStatistics int32
wMaxSegmentSize int16
wNumberMCFilters int16
bNumberPowerFilters int8
} [packed]
usb_cdc_dmm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_DMM_TYPE, int8]
bcdVersion int16
wMaxCommand int16
} [packed]
usb_cdc_mdlm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_TYPE, int8]
bcdVersion int16
bGUID usb_cdc_ecm_mbm_guid
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L61
usb_cdc_ecm_mbm_guid {
id0 const[0x14f5e048ba817a3, int64]
id1 const[0x2a397ecbffc007a6, int64]
} [packed]
usb_cdc_mdlm_detail_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_DETAIL_TYPE, int8]
bGuidDescriptorType int8
bDetailData array[int8, 0:256]
} [packed]
usb_cdc_obex_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_OBEX_TYPE, int8]
bcdVersion int16
} [packed]
usb_cdc_ncm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NCM_TYPE, int8]
bcdNcmVersion int16
bmNetworkCapabilities flags[usb_cdc_ncm_ncaps, int8]
} [packed]
usb_cdc_ncm_ncaps = USB_CDC_NCM_NCAP_ETH_FILTER, USB_CDC_NCM_NCAP_NET_ADDRESS, USB_CDC_NCM_NCAP_ENCAP_COMMAND, USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE, USB_CDC_NCM_NCAP_CRC_MODE, USB_CDC_NCM_NCAP_NTB_INPUT_SIZE
usb_cdc_mbim_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_TYPE, int8]
bcdMBIMVersion int16
wMaxControlMessage int16
bNumberFilters int8
bMaxFilterSize int8
wMaxSegmentSize int16
bmNetworkCapabilities int8
} [packed]
usb_cdc_mbim_extended_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_EXTENDED_TYPE, int8]
bcdMBIMExtendedVersion int16
bMaxOutstandingCommandMessages int8
wMTU int16
} [packed]
vusb_descriptors_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
usb_cdc_ecm_mac {
# This is a UTF16 encoded string "424242424242".
data0 const[0x3400320034003200, int64be]
data1 const[0x3400320034003200, int64be]
data2 const[0x3400320034003200, int64be]
} [packed]
vusb_responses_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC NCM class specific descriptions.
# CDC NCM is based on CDC ECM, so some of the descriptions are reused.
# https://www.usb.org/document-library/network-control-model-devices-specification-v10-and-errata-and-adopters-agreement
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ncm.c
resource fd_usb_cdc_ncm[fd_usb]
syz_usb_connect$cdc_ncm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ncm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ncm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ncm(fd fd_usb_cdc_ncm, descs ptr[in, vusb_descriptors_cdc_ncm], resps ptr[in, vusb_responses_cdc_ncm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ncm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ncm, 1]]
} [packed]
usb_config_descriptor_cdc_ncm {
inner usb_config_descriptor_t[const[1, int8], const[2, int8], usb_interface_descriptors_cdc_ncm]
} [packed]
usb_interface_descriptors_cdc_ncm {
control usb_interface_descriptor_fixed_t[0, CDC_NCM_COMM_ALTSETTING_NCM, 1, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, usb_cdc_header_ncm, usb_endpoint_descriptor_cdc_ecm_notify]
data_nop usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, void]
data usb_interface_descriptor_fixed_t[1, CDC_NCM_DATA_ALTSETTING_NCM, 2, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, usb_endpoint_descriptors_cdc_ncm_data]
} [packed]
usb_endpoint_descriptors_cdc_ncm_data {
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ncm.c#L798
usb_cdc_header_ncm {
union usb_cdc_union_desc_t[0, 1]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
ncm usb_cdc_ncm_desc
other array[usb_cdc_header_ncm_other, 0:6]
} [packed]
usb_cdc_header_ncm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
vusb_descriptors_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
vusb_responses_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_CDC_GET_NTB_PARAMETERS ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_PARAMETERS, usb_cdc_ncm_ntb_parameters]]
USB_CDC_GET_NTB_INPUT_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_INPUT_SIZE, int32]]
USB_CDC_GET_NTB_FORMAT ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_FORMAT, int16[0:1]]]
USB_CDC_GET_MAX_DATAGRAM_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_MAX_DATAGRAM_SIZE, int16]]
USB_CDC_GET_CRC_MODE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_CRC_MODE, int16[0:1]]]
} [packed]
usb_cdc_ncm_ntb_parameters {
wLength int16
bmNtbFormatsSupported int16
dwNtbInMaxSize int32
wNdpInDivisor int16
wNdpInPayloadRemainder int16
wNdpInAlignment int16
wPadding1 int16
dwNtbOutMaxSize int32
wNdpOutDivisor int16
wNdpOutPayloadRemainder int16
wNdpOutAlignment int16
wNtbOutMaxDatagrams int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC1 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1_legacy.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
# TODO: find out which /dev/ files are created by connected UAC1 devices and add descriptions for those.
resource fd_usb_uac1[fd_usb]
syz_usb_connect$uac1(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac1], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac1 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac1(fd fd_usb_uac1, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac1 {
inner usb_device_descriptor_t[0, 0, 0, 0x1d6b, 0x101, 64, array[usb_config_descriptor_uac1, 1]]
} [packed]
usb_config_descriptor_uac1 {
inner usb_config_descriptor_t[const[1, int8], const[3, int8], usb_interface_descriptors_uac1]
} [packed]
# TODO: control interface might have and optional interrupt endpoint.
usb_interface_descriptors_uac1 {
inner usb_interface_descriptors_uac1_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac1_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, 0, uac_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC uses IDs to make it possible for terminals and units to refer to each other.
# We don't have a way to describe this, so just use a limited number of ids.
type uac_id int8[1:6]
uac_control_iface_extra_descriptors {
header uac1_ac_header_descriptor
others array[uac_control_iface_extra_descriptor, 0:6]
} [packed]
uac1_ac_header_descriptor {
bLength const[UAC_DT_AC_HEADER_LENGTH, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdADC int16
wTotalLength len[uac_control_iface_extra_descriptors, int16]
bInCollection const[F_AUDIO_NUM_INTERFACES, int8]
# These must match interfaces numbers.
baInterfaceNr0 const[1, int8]
baInterfaceNr1 const[2, int8]
} [packed]
uac_control_iface_extra_descriptor [
input_terminal uac_input_terminal_descriptor
output_terminal uac1_output_terminal_descriptor
mixer_unit uac_mixer_unit_descriptor
selector_unit uac_selector_unit_descriptor
feature_unit uac_feature_unit_descriptor
processing_unit uac_processing_unit_descriptor
extension_unit uac_extension_unit_descriptor
] [varlen]
define F_AUDIO_NUM_INTERFACES 2
define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
uac_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bNrChannels int8
wChannelConfig int16
iChannelNames int8
iTerminal int8
} [packed]
# The following list contains input terminal types and inout terminal types.
uac_input_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_INPUT_TERMINAL_UNDEFINED, UAC_INPUT_TERMINAL_MICROPHONE, UAC_INPUT_TERMINAL_DESKTOP_MICROPHONE, UAC_INPUT_TERMINAL_PERSONAL_MICROPHONE, UAC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE, UAC_INPUT_TERMINAL_MICROPHONE_ARRAY, UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
# The following list contains output terminal types and inout terminal types.
uac_output_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_OUTPUT_TERMINAL_UNDEFINED, UAC_OUTPUT_TERMINAL_SPEAKER, UAC_OUTPUT_TERMINAL_HEADPHONES, UAC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO, UAC_OUTPUT_TERMINAL_DESKTOP_SPEAKER, UAC_OUTPUT_TERMINAL_ROOM_SPEAKER, UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER, UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
uac1_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
iTerminal int8
} [packed]
uac_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_selector_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_SELECTOR_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bControlSize len[bmaControls, int8]
bmaControls array[flags[uac_feature_unit_controls, int16], 1:6]
iFeature int8
} [packed]
uac_feature_unit_controls = UAC_FU_MUTE, UAC_FU_VOLUME, UAC_FU_BASS, UAC_FU_MID, UAC_FU_TREBLE, UAC_FU_GRAPHIC_EQUALIZER, UAC_FU_AUTOMATIC_GAIN, UAC_FU_DELAY, UAC_FU_BASS_BOOST, UAC_FU_LOUDNESS
uac_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_PROCESSING_UNIT, int8]
bUnitID uac_id
wProcessType flags[uac_processing_unit_types, int16]
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_processing_unit_types = UAC_PROCESS_UNDEFINED, UAC_PROCESS_UP_DOWNMIX, UAC_PROCESS_DOLBY_PROLOGIC, UAC_PROCESS_STEREO_EXTENDER, UAC_PROCESS_REVERB, UAC_PROCESS_CHORUS, UAC_PROCESS_DYN_RANGE_COMP
uac_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_EXTENSION_UNIT, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_iface_extra_descriptors {
others array[uac_as_iface_extra_descriptor, 0:6]
} [packed]
uac_as_iface_extra_descriptor [
as_header uac1_as_header_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
format_type_i_ext uac_format_type_i_ext_descriptor
] [varlen]
uac1_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bDelay int8
wFormatTag flags[uac_format_tags, int16]
} [packed]
uac_format_tags = UAC_FORMAT_TYPE_I_UNDEFINED, UAC_FORMAT_TYPE_I_PCM, UAC_FORMAT_TYPE_I_PCM8, UAC_FORMAT_TYPE_I_IEEE_FLOAT, UAC_FORMAT_TYPE_I_ALAW, UAC_FORMAT_TYPE_I_MULAW, UAC_FORMAT_TYPE_II_MPEG, UAC_FORMAT_TYPE_II_AC3
uac_usb_format_types_i = UAC_FORMAT_TYPE_I, UAC_FORMAT_TYPE_II, UAC_FORMAT_TYPE_III, UAC_FORMAT_TYPE_UNDEFINED
uac_format_type_i_continuous_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tLowerSamFreq array[int8, 0:3]
tUpperSamFreq array[int8, 0:3]
} [packed]
uac_format_type_i_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
uac_format_type_ii_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
uac_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
define USB_ENDPOINT_UAC1_AS_OUT_ADDRESS (1 | USB_DIR_OUT)
define USB_ENDPOINT_UAC1_AS_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_UAC1_AS_ATTRIBUTES (USB_ENDPOINT_SYNC_ADAPTIVE | USB_ENDPOINT_XFER_ISOC)
uac_iso_ep_attributes = USB_ENDPOINT_SYNCTYPE, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC
uac_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC_EP_GENERAL, int8]
bmAttributes flags[uac_iso_ep_attributes, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
vusb_descriptors_uac1 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_uac1 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
audio_UAC_GET_CUR ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_CUR, array[int8, 1:3]]]
audio_UAC_GET_MIN ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MIN, array[int8, 1:3]]]
audio_UAC_GET_MAX ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MAX, array[int8, 1:3]]]
audio_UAC_GET_RES ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_RES, array[int8, 1:4]]]
audio_UAC_GET_MEM ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MEM, array[int8, 3]]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC2 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac2.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac2[fd_usb]
syz_usb_connect$uac2(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac2], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac2 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac2(fd fd_usb_uac2, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac2 {
inner usb_device_descriptor_t[0, 0, 0, 0x41e, 0x3000, 64, array[usb_config_descriptor_uac2, 1]]
} [packed]
usb_config_descriptor_uac2 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac2_interface_assoc_descriptor, usb_interface_descriptors_uac2]
} [packed]
uac2_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[audio_function_category_types, int8]
bFunctionProtocol const[UAC_VERSION_2, int8]
iFunction int8
} [packed]
audio_function_category_types = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER
usb_interface_descriptors_uac2 {
inner usb_interface_descriptors_uac2_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac2_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_2, uac2_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptors {
header uac2_ac_header_descriptor
others array[uac2_control_iface_extra_descriptor, 0:6]
} [packed]
uac2_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bcdADC int16
bCategory flags[uac2_feature_unit_controls, int8]
wTotalLength len[uac2_control_iface_extra_descriptors, int16]
bmControls int8
} [packed]
uac2_feature_unit_controls = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER, uac_feature_unit_controls
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_as_iface_extra_descriptors {
others array[uac2_as_iface_extra_descriptor, 0:6]
} [packed]
uac2_as_iface_extra_descriptor [
as_header uac2_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
uac2_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int8
bFormatType flags[uac_usb_format_types_i, int8]
bmFormats flags[uac_format_tags, int32]
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
} [packed]
b_sub_slot_sizes = 1, 2, 3, 4
uac2_format_type_i_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize flags[b_sub_slot_sizes, int8]
bBitResolution int8
} [packed]
uac2_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac_format_type_ii_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bHeaderLength int8
bSideBandProtocol int8
} [packed]
uac_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac2_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubtype const[UAC_EP_GENERAL, int8]
bmAttributes flags[csep_bm_attributes, int8]
bmControls flags[csep_bm_controls, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
csep_bm_attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, UAC_EP_CS_ATTR_PITCH_CONTROL, UAC_EP_CS_ATTR_FILL_MAX
csep_bm_controls = UAC2_CONTROL_PITCH, UAC2_CONTROL_DATA_OVERRUN, UAC2_CONTROL_DATA_UNDERRUN
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptor [
input_terminal uac2_input_terminal_descriptor
output_terminal uac2_output_terminal_descriptor
mixer_unit uac2_mixer_unit_descriptor
selector_unit uac2_clock_selector_descriptor
feature_unit uac2_feature_unit_descriptor
processing_unit uac2_processing_unit_descriptor
extension_unit uac2_extension_unit_descriptor
effect_unit uac2_effect_unit_descriptor
sample_rate uac2_sample_rate_descriptor
source_unit uac2_clock_source_descriptor
multiply_unit uac2_clock_multiplier_descriptor
] [varlen]
uac2_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
bmControls int8
iTerminal int8
} [packed]
uac2_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal int8
bSourceID uac_id
bCSourceID int8
bmControls int16
iTerminal int8
} [packed]
uac2_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Figure out if bmControls and iClockSelector should be a part of this structure.
uac2_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
# TODO: Verify coverage.
uac2_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_PROCESSING_UNIT_V2, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_processing_unit_types = UAC2_PROCESS_UNDEFINED, UAC2_PROCESS_UP_DOWNMIX, UAC2_PROCESS_DOLBY_PROLOCIC, UAC2_PROCESS_STEREO_EXTENDER
uac2_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_EXTENSION_UNIT_V2, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Verify coverage.
uac2_effect_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_EFFECT_UNIT, int8]
bUnitID uac_id
wEffectType flags[uac2_effect_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_effect_unit_types = UAC2_EFFECT_UNDEFINED, UAC2_EFFECT_PARAM_EQ, UAC2_EFFECT_REVERB, UAC2_EFFECT_MOD_DELAY, UAC2_EFFECT_DYN_RANGE_COMP
uac2_sample_rate_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_SAMPLE_RATE_CONVERTER, int8]
bUnitID uac_id
wProcessType flags[uac2_processing_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_feature_unit_controls, int16], 1:6]
} [packed]
uac2_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac2_clock_bmattribute_types, int8]
bmControls int8
bAssocTerminal int8
iClockSource flags[uac2_clock_source_types, int8]
} [packed]
uac2_clock_bmattribute_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_source_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int8
iClockMultiplier int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC3 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac3.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac3[fd_usb]
syz_usb_connect$uac3(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac3], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac3 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac3(fd fd_usb_uac3, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac3 {
inner usb_device_descriptor_t[0, 0, 0, 0x582, 0x582, 64, array[usb_config_descriptor_uac3, 1]]
} [packed]
usb_config_descriptor_uac3 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac3_interface_assoc_descriptor, usb_interface_descriptors_uac3]
} [packed]
uac3_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[uac3_all_subclasses, int8]
bFunctionProtocol const[UAC_VERSION_3, int8]
iFunction int8
} [packed]
usb_interface_descriptors_uac3 {
inner usb_interface_descriptors_uac3_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac3_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_3, uac3_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptors {
header uac3_ac_header_descriptor
others array[uac3_control_iface_extra_descriptor, 0:6]
} [packed]
uac3_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bCategory flags[uac3_feature_unit_controls, int8]
wTotalLength len[uac3_control_iface_extra_descriptors, int16]
bmControls int32
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_as_iface_extra_descriptors {
others array[uac3_as_iface_extra_descriptor, 0:6]
} [packed]
uac3_as_iface_extra_descriptor [
as_header uac3_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
# TODO: Figure out how wClusterDescrID is used in the kernel.
uac3_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int32
wClusterDescrID int16
bmFormats flags[uac_format_tags, int64]
bSubslotSize int8
bBitResolution int8
bmAuxProtocols int16
bControlSize int8
} [packed]
uac3_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC3_CS_ENDPOINT, int8]
bmControls int32
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptor [
input_terminal uac3_input_terminal_descriptor
output_terminal uac3_output_terminal_descriptor
mixer_unit uac3_mixer_unit_descriptor
selector_unit uac3_clock_selector_descriptor
source_unit uac3_clock_source_descriptor
multiply_unit uac3_clock_multiplier_descriptor
feature_unit uac3_feature_unit_descriptor
processing_unit uac3_processing_unit_descriptor
extension_unit uac3_extension_unit_descriptor
power_domain uac3_power_domain_descriptor
cluster_info_segment uac3_cluster_information_segment_descriptor
# Only cluster information segment is currently used in the kernel.See: sound/usb/stream.c
# cluster_segment uac3_cluster_segment_descriptor
# cluster_end_segment uac3_cluster_end_segment_descriptor
# The following units are not yet supported by the kernel.
# See audio_validators[] in sound/usb/validate.c:
# effect_unit uac3_effect_unit_descriptor
# sample_rate uac3_sample_rate_descriptor
# connectors_unit uac3_connectors_unit_descriptor
# extended_term_unit uac3_extended_terminal_unit
] [varlen]
uac3_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bmControls int32
wClusterDescrID int16
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
bCSourceID int8
bmControls int32
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac3_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
uac3_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac3_clock_bmattribute_types, int8]
bmControls int32
bReferenceTerminal int8
wClockSourceStr int16
} [packed]
uac3_clock_bmattribute_types = UAC3_CLOCK_SOURCE_TYPE_EXT, UAC3_CLOCK_SOURCE_TYPE_INT, UAC3_CLOCK_SOURCE_ASYNC, UAC3_CLOCK_SOURCE_SYNCED_TO_SOF
uac3_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int32
wCMultiplierDescrStr int16
} [packed]
uac3_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_feature_unit_controls, int32], 1:6]
} [packed]
uac3_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_PROCESSING_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_processing_unit_types = UAC3_PROCESS_UNDEFINED, UAC3_PROCESS_UP_DOWNMIX, UAC3_PROCESS_STEREO_EXTENDER, UAC3_PROCESS_MULTI_FUNCTION
uac3_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_EXTENSION_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_power_domain_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_POWER_DOMAIN, int8]
bPowerDomainID int8
waRecoveryTime1 int16
waRecoveryTime2 int16
bNrEntities int8
baEntityID array[int8, 0:8]
} [packed]
uac3_cluster_information_segment_descriptor {
bLength len[parent, int16]
bSegmentType const[UAC3_CHANNEL_INFORMATION, int8]
bChPurpose flags[uac3_cluster_channel_purposes, int8]
bChRelationship flags[uac3_cluster_channel_relationships, int8]
bChGroupID int8
} [packed]
uac3_cluster_channel_purposes = UAC3_PURPOSE_UNDEFINED, UAC3_PURPOSE_GENERIC_AUDIO, UAC3_PURPOSE_VOICE, UAC3_PURPOSE_SPEECH, UAC3_PURPOSE_AMBIENT, UAC3_PURPOSE_REFERENCE, UAC3_PURPOSE_ULTRASONIC, UAC3_PURPOSE_VIBROKINETIC, UAC3_PURPOSE_NON_AUDIO
uac3_cluster_channel_relationships = UAC3_CH_RELATIONSHIP_UNDEFINED, UAC3_CH_MONO, UAC3_CH_LEFT, UAC3_CH_RIGHT, UAC3_CH_ARRAY, UAC3_CH_PATTERN_X, UAC3_CH_PATTERN_Y, UAC3_CH_PATTERN_A, UAC3_CH_PATTERN_B, UAC3_CH_PATTERN_M, UAC3_CH_PATTERN_S, UAC3_CH_FRONT_LEFT, UAC3_CH_FRONT_RIGHT, UAC3_CH_FRONT_CENTER, UAC3_CH_FRONT_LEFT_OF_CENTER, UAC3_CH_FRONT_RIGHT_OF_CENTER, UAC3_CH_FRONT_WIDE_LEFT, UAC3_CH_FRONT_WIDE_RIGHT, UAC3_CH_SIDE_LEFT, UAC3_CH_SIDE_RIGHT, UAC3_CH_SURROUND_ARRAY_LEFT, UAC3_CH_SURROUND_ARRAY_RIGHT, UAC3_CH_BACK_LEFT, UAC3_CH_BACK_RIGHT, UAC3_CH_BACK_CENTER, UAC3_CH_BACK_LEFT_OF_CENTER, UAC3_CH_BACK_RIGHT_OF_CENTER, UAC3_CH_BACK_WIDE_LEFT, UAC3_CH_BACK_WIDE_RIGHT, UAC3_CH_TOP_CENTER, UAC3_CH_TOP_FRONT_LEFT, UAC3_CH_TOP_FRONT_RIGHT, UAC3_CH_TOP_FRONT_CENTER, UAC3_CH_TOP_FRONT_LOC, UAC3_CH_TOP_FRONT_ROC, UAC3_CH_TOP_FRONT_WIDE_LEFT, UAC3_CH_TOP_FRONT_WIDE_RIGHT, UAC3_CH_TOP_SIDE_LEFT, UAC3_CH_TOP_SIDE_RIGHT, UAC3_CH_TOP_SURR_ARRAY_LEFT, UAC3_CH_TOP_SURR_ARRAY_RIGHT, UAC3_CH_TOP_BACK_LEFT, UAC3_CH_TOP_BACK_RIGHT, UAC3_CH_TOP_BACK_CENTER, UAC3_CH_TOP_BACK_LOC, UAC3_CH_TOP_BACK_ROC, UAC3_CH_TOP_BACK_WIDE_LEFT, UAC3_CH_TOP_BACK_WIDE_RIGHT, UAC3_CH_BOTTOM_CENTER, UAC3_CH_BOTTOM_FRONT_LEFT, UAC3_CH_BOTTOM_FRONT_RIGHT, UAC3_CH_BOTTOM_FRONT_CENTER, UAC3_CH_BOTTOM_FRONT_LOC, UAC3_CH_BOTTOM_FRONT_ROC, UAC3_CH_BOTTOM_FRONT_WIDE_LEFT, UAC3_CH_BOTTOM_FRONT_WIDE_RIGHT, UAC3_CH_BOTTOM_SIDE_LEFT, UAC3_CH_BOTTOM_SIDE_RIGHT, UAC3_CH_BOTTOM_SURR_ARRAY_LEFT, UAC3_CH_BOTTOM_SURR_ARRAY_RIGHT, UAC3_CH_BOTTOM_BACK_LEFT, UAC3_CH_BOTTOM_BACK_RIGHT, UAC3_CH_BOTTOM_BACK_CENTER, UAC3_CH_BOTTOM_BACK_LOC, UAC3_CH_BOTTOM_BACK_ROC, UAC3_CH_BOTTOM_BACK_WIDE_LEFT, UAC3_CH_BOTTOM_BACK_WIDE_RIGHT, UAC3_CH_LOW_FREQUENCY_EFFECTS, UAC3_CH_LFE_LEFT, UAC3_CH_LFE_RIGHT, UAC3_CH_HEADPHONE_LEFT, UAC3_CH_HEADPHONE_RIGHT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# This list consists of uac3_func_subclasses + uac3_badd_classes.
uac3_all_subclasses = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0, UAC3_FUNCTION_SUBCLASS_GENERIC_IO, UAC3_FUNCTION_SUBCLASS_HEADPHONE, UAC3_FUNCTION_SUBCLASS_SPEAKER, UAC3_FUNCTION_SUBCLASS_MICROPHONE, UAC3_FUNCTION_SUBCLASS_HEADSET, UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE
uac3_feature_unit_controls = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_DESKTOP_SPEAKER, UAC3_FUNCTION_HOME_THEATER, UAC3_FUNCTION_MICROPHONE, UAC3_FUNCTION_HEADSET, UAC3_FUNCTION_TELEPHONE, UAC3_FUNCTION_CONVERTER, UAC3_FUNCTION_SOUND_RECORDER, UAC3_FUNCTION_IO_BOX, UAC3_FUNCTION_MUSICAL_INSTRUMENT, UAC3_FUNCTION_PRO_AUDIO, UAC3_FUNCTION_AUDIO_VIDEO, UAC3_FUNCTION_CONTROL_PANEL, UAC3_FUNCTION_HEADPHONE, UAC3_FUNCTION_GENERIC_SPEAKER, UAC3_FUNCTION_HEADSET_ADAPTER, UAC3_FUNCTION_SPEAKERPHONE, UAC3_FUNCTION_OTHER
# TODO: Support uac3 badd profiles. See sound/usb/mixer.c: snd_usb_mixer_controls_badd()
# uac3_badd_endpoint_descriptor {
# inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
# } [packed]
#uac3_badd_maxsizes = UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# MIDI device class specific descriptions.
# https://www.usb.org/sites/default/files/midi10.pdf
# https://elixir.bootlin.com/linux/latest/source/sound/usb/midi.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_midi.c
syz_usb_connect$midi(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_midi], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
usb_device_descriptor_midi {
inner usb_device_descriptor_t[0, 0, 0, 0x1430, 0x474b, 64, array[usb_config_descriptor_midi, 1]]
} [packed]
usb_config_descriptor_midi {
inner usb_config_descriptor_t[const[1, int8], const[1, int8], usb_interface_descriptors_midi]
} [packed]
usb_interface_descriptors_midi {
inner usb_interface_descriptors_midi_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_midi_inner {
control usb_interface_descriptor_eps_array_t[const[0, int8], const[0, int8], const[USB_CLASS_AUDIO, int8], const[USB_SUBCLASS_MIDISTREAMING, int8], flags[uac_version_types, int8], array[usb_midi_iface_extra], array[usb_endpoint_descriptor_midi, 0:8]]
} [packed]
usb_endpoint_descriptor_midi {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], usb_ms_endpoint_descriptor]
} [packed]
midi_jack_type = USB_MS_EMBEDDED, USB_MS_EXTERNAL
uac_version_types = UAC_VERSION_1, UAC_VERSION_2, UAC_VERSION_3
usb_ms_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[USB_MS_GENERAL, int8]
bNumEmbMIDIJack len[baAssocJackID, int8]
baAssocJackID array[int8, 0:16]
} [packed]
usb_midi_iface_extra [
ms_header usb_ms_header_descriptor
midi_in_jack usb_midi_in_jack_descriptor
midi_out_jack usb_midi_out_jack_descriptor
] [varlen]
usb_ms_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdMSC int16
wTotalLength len[parent, int16]
} [packed]
usb_midi_in_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_IN_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
iJack int8
} [packed]
usb_midi_out_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_OUT_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
bNrInputPins len[pins, int8]
pins array[usb_midi_source_pin]
iJack int8
} [packed]
usb_midi_source_pin {
baSourceID int8
baSourcePin int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# ath9k driver specific descriptions.
include <drivers/net/wireless/ath/ath9k/htc_hst.h>
include <drivers/net/wireless/ath/ath9k/hif_usb.h>
define USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS (1)
define USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_IN_ADDRESS (3 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS (4)
define USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS (5)
define USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS (6)
resource fd_usb_ath9k[fd_usb]
syz_usb_connect_ath9k(speed const[USB_SPEED_HIGH], dev_len len[dev], dev ptr[in, usb_device_descriptor_ath9k], conn_descs const[0]) fd_usb_ath9k (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_ep_write$ath9k_ep1(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS], len bytesize[data], data ptr[in, ath9k_bulk_frame]) (timeout[300], remote_cover)
syz_usb_ep_write$ath9k_ep2(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS], len bytesize[data], data ptr[in, htc_frame]) (timeout[300], remote_cover)
usb_device_descriptor_ath9k {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xcf3, 0x9271, 0x108, array[usb_config_descriptor_ath9k, 1]]
} [packed]
usb_config_descriptor_ath9k {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_ath9k]
} [packed]
usb_interface_descriptor_ath9k {
iface usb_interface_descriptor_fixed_t[0, 0, 6, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_ath9k]
} [packed]
usb_endpoint_descriptors_ath9k {
bulk_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
int_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
bulk_extra1 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_extra2 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
} [packed]
define USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_ATH9K_INT_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
ath9k_bulk_frame {
packets array[ath9k_bulk_packet]
} [packed]
ath9k_bulk_packet {
pkt_len len[data, int16]
pkt_tag const[ATH_USB_RX_STREAM_MODE_TAG, int16]
data array[int8]
} [packed, align[4]]
htc_frame [
ready htc_ready_frame
conn_svc_rsp htc_conn_svc_rsp_frame
generic htc_generic_frame
] [varlen]
# This is actually wrong, as the driver is buggy and doesn't skip the header
# before processing the frame payload, but let's leave it like thise for now.
htc_ready_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_ready_msg
} [packed]
htc_ready_msg {
message_id const[HTC_MSG_READY_ID, int16be]
credits int16be
credit_size int16be
max_endpoints int8
pad int8
} [packed]
htc_conn_svc_rsp_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_conn_svc_rspmsg
} [packed]
htc_conn_svc_rspmsg {
message_id const[HTC_MSG_CONNECT_SERVICE_RESPONSE_ID, int16be]
service_id flags[htc_svcs, int16be]
status const[HTC_SERVICE_SUCCESS, int8]
endpoint_id int8
max_msg_len int16be
svc_meta_len int8
pad int8
} [packed]
htc_svcs = HTC_CTRL_RSVD_SVC, HTC_LOOPBACK_RSVD_SVC, WMI_CONTROL_SVC, WMI_BEACON_SVC, WMI_CAB_SVC, WMI_UAPSD_SVC, WMI_MGMT_SVC, WMI_DATA_VO_SVC, WMI_DATA_VI_SVC, WMI_DATA_BE_SVC, WMI_DATA_BE_SVC
htc_generic_frame {
endpoint_id int8[0:8]
flags flags[htc_frame_flags, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload array[int8, 0:256]
} [packed]
htc_frame_flags = HTC_FLAGS_RECV_TRAILER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Assorted driver-specific descriptions of generic syz_* calls' variants.
# Generic calls such as syz_usb_connect() and syz_usb_control_io() should be enough
# (in theory) to emulate a proper device and finish driver probes without a hitch.
# However, there are cases when syzkaller fails to come up with correct inputs to achieve it.
# Use fixed descriptors to quickly pass through probe() to access select drivers' post-probe functionality.
# It is important to note that, one way or another, drivers in question require multiple control requests
# between a driver and a device processed during probe(). Descriptions below do not deal with specific
# CTRL requests as such (except for basic information included in vusb_responses_XXX). Instead, rely on
# seeds, created both manually and with syzkaller's help. For examples, see sys/linux/test/vusb_XXX.
# Common constants for endpoint descriptors.
define USB_ENDPOINT_BULK_ATTR (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_INT_ATTR (USB_ENDPOINT_XFER_INT)
define USB_FIXED_ENDPOINT_BULK_IN_ADDR (1 | USB_DIR_IN)
define USB_FIXED_ENDPOINT_BULK_OUT_ADDR (2)
define USB_FIXED_ENDPOINT_INT_IN_ADDR (3 | USB_DIR_IN)
define USB_RECIP_DEVICE 0x00
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# rtl8150 driver specific descriptions.
resource fd_usb_rtl8150[fd_usb]
syz_usb_connect$rtl8150(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_rtl8150], conn_descs const[0]) fd_usb_rtl8150 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$rtl8150(fd fd_usb_rtl8150, descs ptr[in, vusb_descriptors_rtl8150], resps ptr[in, vusb_responses_rtl8150]) (timeout[300], remote_cover)
usb_device_descriptor_rtl8150 {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xbda, 0x8150, 0, array[usb_config_descriptor_rtl8150, 1]]
} [packed]
usb_config_descriptor_rtl8150 {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_rtl8150]
} [packed]
usb_interface_descriptor_rtl8150 {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_rtl8150]
} [packed]
usb_endpoint_descriptors_rtl8150 {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
RTL8150_REQ_GET_REGS ptr[in, vusb_response_t[RTL8150_REQT_READ, RTL8150_REQ_GET_REGS, array[int8, 0:6]]]
RTL8150_REQ_SET_REGS ptr[in, vusb_response_t[RTL8150_REQT_WRITE, RTL8150_REQ_SET_REGS, array[int8, 0:6]]]
} [packed]
define RTL8150_REQ_GET_REGS 0x05
define RTL8150_REQ_SET_REGS 0x05
define RTL8150_REQT_READ 0xc0
define RTL8150_REQT_WRITE 0x40
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# sierra_net driver specific descriptions.
resource fd_usb_sierra_net[fd_usb]
syz_usb_connect$sierra_net(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_sierra_net], conn_descs const[0]) fd_usb_sierra_net (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$sierra_net(fd fd_usb_sierra_net, descs ptr[in, vusb_descriptors_sierra_net], resps ptr[in, vusb_responses_sierra_net]) (timeout[300], remote_cover)
usb_device_descriptor_sierra_net {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x1199, 0x68a3, 0, array[usb_config_descriptor_sierra_net, 1]]
} [packed]
usb_config_descriptor_sierra_net {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_sierra_net]
} [packed]
usb_interface_descriptor_sierra_net {
iface usb_interface_descriptor_fixed_t[7, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_sierra_net]
} [packed]
# sierra_net driver does not expect fixed ep addresses, so refrain from being too specific here.
# As long as we ensure there are 3 endpoints, 2 bulk and 1 int, syzkaller should figure it out.
usb_endpoint_descriptors_sierra_net {
bulk_in usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
bulk_out usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
status usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_INT_ATTR, int8], void]
} [packed]
vusb_descriptors_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_CDC_GET_ENCAPSULATED_RESPONSE ptr[in, vusb_response_t[SIERRA_CMD_TYPE_IN, USB_CDC_GET_ENCAPSULATED_RESPONSE, array[int8, 1024]]]
USB_CDC_SEND_ENCAPSULATED_COMMANDT ptr[in, vusb_response_t[SIERRA_CMD_TYPE_OUT, USB_CDC_SEND_ENCAPSULATED_COMMAND, array[int8, 0:4]]]
} [packed]
define SIERRA_CMD_TYPE_IN (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
define SIERRA_CMD_TYPE_OUT (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# lan78xx driver specific descriptions.
# While these syz_* variants noticably help with the probe() process, they are not enough.
# This is due to a high number of control requests expected between the driver and the device.
include <drivers/net/usb/smsc95xx.h>
resource fd_usb_lan78xx[fd_usb]
syz_usb_connect$lan78xx(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_lan78xx], conn_descs const[0]) fd_usb_lan78xx (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$lan78xx(fd fd_usb_lan78xx, descs ptr[in, vusb_descriptors_lan78xx], resps ptr[in, vusb_responses_lan78xx]) (timeout[300], remote_cover)
usb_device_descriptor_lan78xx {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x424, 0x7850, 0, array[usb_config_descriptor_lan78xx, 1]]
} [packed]
usb_config_descriptor_lan78xx {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_lan78xx]
} [packed]
usb_interface_descriptor_lan78xx {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_lan78xx]
} [packed]
usb_endpoint_descriptors_lan78xx {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_VENDOR_REQUEST_READ_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_READ_REGISTER, int32]]
USB_VENDOR_REQUEST_WRITE_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_OUT, USB_VENDOR_REQUEST_WRITE_REGISTER, int32]]
USB_VENDOR_REQUEST_GET_STATS ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_GET_STATS, array[int8, 47]]]
} [packed]
define LAN78XX_REG_TYPE_IN (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
define LAN78XX_REG_TYPE_OUT (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
]
|
| 288/2 |
2026/07/30 13:03 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 103085
output: 501
thoughts: 1484
Thoughts: **A Deep Dive into the `au0828` USB Driver Vulnerability**
Okay, so I'm digging into this `au0828` driver, and things are getting interesting. My initial thought was about how to get more than four interfaces to play nice with the USB device descriptor, especially considering the `au0828` driver needs a specific alternate setting. I saw `syz_usb_connect` takes `usb_device_descriptor`, and that has a limit of four interfaces. I briefly considered using `ANY` or raw byte arrays, but that's a no-go with how Syzkaller's structured.
Then it hit me: what if I don't *need* the analog registration to succeed? If `au0828_analog_register` fails, the driver just returns an error, right? And I saw the code goes to `done`, calls `au0828_usb_disconnect` which then calls `au0828_analog_unregister`. I thought, will `au0828_analog_unregister` return a 1? Turns out it will! The return of `au0828_analog_unregister` returning 1 and making `au0828_usb_disconnect` return early depends only on a value set by `id->driver_info` which, crucially, *doesn't* depend on `au0828_analog_register` succeeding. So, if registration fails it's good!
This is where it gets juicy. If I get the early return, `au0828_usb_release(dev)` doesn't get called. And `au0828_i2c_unregister(dev)` won't be called either! So the I2C adapter stays registered! Because `probe` returns an error, the USB core cleans up the interface, but the I2C adapter is still there, registered and its parent is tied to a pointer to the USB device. Now, if I disconnect the USB device *after* `probe` returns an error, the `usb_device` gets freed. *Boom* - dangling pointer! Then I can do an I2C transaction on it and trigger a UAF (Use-After-Free)!
Essentially, I don't even need to open the V4L2 device. The key is the leak of `dev` and the registered I2C adapter. This is a HUGE bug.
Here's the plan to verify this. I'll use `syz_usb_connect` with specific vendor and product IDs (0x2040 and 0x7200), and make sure I *don't* provide alternate setting 5. `au0828_analog_register` will fail, `au0828_usb_disconnect` will be called, `au0828_analog_unregister` will return 1, and so the early return will leak `dev`, leaving the I2C adapter registered. The I then disconnect the USB device and then access the I2C adapter! Let's see if this works!
|
| 289/2 |
2026/07/30 13:03 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{18, 1, 0x200, 0, 0, 0, 64, 0x2040, 0x7200, 0, 0, 0, 0, AUTO, [{{9, 2, AUTO, AUTO, 1, 0, 0x80, 0, "", [{{{9, 4, 0, 0, AUTO, 0, 0, 0, 0, [], []}}}]}}]}}, 0)
r1 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r2 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r3 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r4 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r2, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 290/2 |
2026/07/30 13:03 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 105915
output: 500
thoughts: 1504
Thoughts: **Debugging USB Descriptor Generation**
Okay, here's the deal. I'm getting a "wrong struct arg for 'const'" error at position 9, specifically for `bLength` within the `usb_interface_descriptor_verbose_t` struct. Let me break down my current thought process.
I'm starting by tracing the definitions. `usb_interface_descriptor` uses an `inner` struct, which is `usb_interface_descriptor_eps_array_t`. Looking at the types, `bInterfaceClass` *should* be zero, since it's defined as a `const[0, int8]`. I've confirmed that `bLength` is 9, which is also correct as `const[USB_DT_INTERFACE_SIZE, int8]`.
Now, let's step through the fields of `usb_interface_descriptor_verbose_t`:
1. `bLength = 9` (Correct, `USB_DT_INTERFACE_SIZE`)
2. `bDescriptorType = 4` (Interface)
3. `bInterfaceNumber = 0`
4. `bAlternateSetting = 0`
5. `bNumEndpoints = AUTO`
6. `bInterfaceClass = 0` (Confirmed)
7. `bInterfaceSubClass = 0`
8. `bInterfaceProtocol = 0`
9. `iInterface = 0`
10. `extra = []` (Empty array)
11. `endpoints = []` (Empty array)
I'm passing `int8` for `iInterface` which is correct, and I've provided empty arrays for `extra` and `endpoints`, which makes sense given the type definitions. I'm starting to get a bit stuck here since `bNumEndpoints` is `AUTO`, determined by the `len` of `endpoints`.
The key is this: `usb_interface_descriptor` is composed of `usb_interface_descriptor_eps_array_t`, where `bNumEndpoints` is `AUTO` and determined by the length of the `endpoints` array.
Now let's check the config descriptor. `usb_config_descriptor_ifaces_array_t` and `usb_config_descriptor_t` give us the `usb_config_descriptor_verbose_t` struct. I am providing `[{{{9, 4, 0, 0, AUTO, 0, 0, 0, 0, [], []}}}]`.
After considering the fields in `usb_config_descriptor_verbose_t`:
1. `bLength = 9` (Looks fine)
2. `bDescriptorType = 2` (Config)
3. `wTotalLength = AUTO`
4. `bNumInterfaces = AUTO`
5. `bConfigurationValue = 1`
6. `iConfiguration = 0`
7. `bmAttributes = 0x80`
8. `bMaxPower = 0`
9. `extra = ""` (Empty string)
10. `interfaces = [{{9, 4, 0, 0, AUTO, 0, 0, 0, 0, [], []}}]`
The thing that clicks is the `interfaces` array; it should be an array of `usb_interface_descriptor` which is constructed from the inner `usb_interface_descriptor_eps_array_t`. I'm constructing an interface correctly. Early on I tried an array with non-zero values for `extra`, and that caused the type problem with the array. Since the extra struct now is void it's not a problem!
Okay, let's try the complete structure now!
|
| 291/2 |
2026/07/30 13:04 |
tool |
reproduce-crash |
2m
Args: map[ReproSyz:r0 = syz_usb_connect(3, 0, &AUTO={{18, 1, 0x200, 0, 0, 0, 64, 0x2040, 0x7200, 0, 0, 0, 0, AUTO, [{{9, 2, AUTO, AUTO, 1, 0, 0x80, 0, "", [{{9, 4, 0, 0, AUTO, 0, 0, 0, 0, [], []}}]}}]}}, 0)
r1 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r2 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r3 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r4 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r2, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID:repro/a8b2bc0743561b212b58b65173931b46708db046 ReproducedBugTitle: ReproducedCrashReport:]
|
| 292/2 |
2026/07/30 13:06 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 108813
output: 60
thoughts: 14
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Initial Assessment: Success and Immediate Verification**
Okay, it didn't crash. That's a huge relief. Now, instead of patting myself on the back too soon, my next immediate thought is to systematically verify the success. The crash test went well, but that's just the starting point. Time to dive straight into a comprehensive coverage analysis. We need to ascertain which code paths were executed and, critically, which areas remain untested, particularly around edge cases. I'll need to know the state of the coverage metrics β which branches were hit, which lines weren't, the overall percentage. Only then can I consider this a true pass, or at least a step closer to it.
|
| 293/2 |
2026/07/30 13:06 |
tool |
get-coverage-files |
0m
Args: map[ExecutionCachedID:repro/a8b2bc0743561b212b58b65173931b46708db046]
Results: map[Files:[arch/x86/entry/vsyscall/vsyscall_64.c arch/x86/include/asm/atomic64_64.h arch/x86/include/asm/bitops.h arch/x86/include/asm/compat.h arch/x86/include/asm/cpufeature.h arch/x86/include/asm/irqflags.h arch/x86/include/asm/jump_label.h arch/x86/include/asm/mmu_context.h arch/x86/include/asm/page.h arch/x86/include/asm/pgtable.h arch/x86/include/asm/pkru.h arch/x86/include/asm/preempt.h arch/x86/include/asm/trace/fpu.h arch/x86/kernel/cpu/aperfmperf.c arch/x86/kernel/fpu/context.h arch/x86/kernel/fpu/core.c arch/x86/kernel/fpu/internal.h arch/x86/kernel/fpu/xstate.c arch/x86/kernel/kvm.c arch/x86/kernel/tsc.c arch/x86/mm/fault.c arch/x86/mm/maccess.c arch/x86/mm/pgtable.c arch/x86/pci/common.c arch/x86/pci/direct.c block/blk-cgroup.c drivers/acpi/acpica/nsaccess.c drivers/acpi/acpica/nsdump.c drivers/acpi/acpica/nssearch.c drivers/acpi/acpica/nsutils.c drivers/acpi/acpica/nsxfname.c drivers/acpi/acpica/utascii.c drivers/acpi/acpica/utdebug.c drivers/acpi/acpica/utmutex.c drivers/acpi/acpica/utstring.c drivers/acpi/device_pm.c drivers/acpi/osl.c drivers/acpi/property.c drivers/acpi/utils.c drivers/base/core.c drivers/base/map.c drivers/base/power/qos.c drivers/base/power/runtime.c drivers/base/power/wakeirq.c drivers/char/misc.c drivers/i2c/busses/i2c-i801.c drivers/i2c/i2c-core-base.c drivers/i2c/i2c-core-smbus.c drivers/i2c/i2c-core.h drivers/i2c/i2c-dev.c drivers/pci/access.c drivers/pci/ats.c drivers/pci/host-bridge.c drivers/pci/iov.c drivers/pci/msi/api.c drivers/pci/msi/msi.c drivers/pci/pci-acpi.c drivers/pci/pci-driver.c drivers/pci/pci.c drivers/pci/pcie/aer.c drivers/pci/pcie/aspm.c drivers/pci/quirks.c drivers/pci/rebar.c drivers/pci/vc.c drivers/usb/gadget/legacy/raw_gadget.c fs/char_dev.c fs/d_path.c fs/dcache.c fs/file.c fs/file_table.c fs/ioctl.c fs/libfs.c fs/mnt_idmapping.c fs/namei.c fs/namespace.c fs/notify/fsnotify.c fs/open.c include/acpi/acpi_bus.h include/asm-generic/bitops/instrumented-non-atomic.h include/linux/atomic/atomic-arch-fallback.h include/linux/atomic/atomic-instrumented.h include/linux/atomic/atomic-long.h include/linux/audit.h include/linux/bit_spinlock.h include/linux/cgroup.h include/linux/clockchips.h include/linux/cpumask.h include/linux/cred.h include/linux/dcache.h include/linux/delayed_call.h include/linux/device.h include/linux/device_cgroup.h include/linux/err.h include/linux/file.h include/linux/file_ref.h include/linux/filelock.h include/linux/find.h include/linux/folio_batch.h include/linux/fs.h include/linux/fs/super.h include/linux/fsnotify.h include/linux/fsnotify_backend.h include/linux/hrtimer.h include/linux/jiffies.h include/linux/jump_label.h include/linux/kernel.h include/linux/kref.h include/linux/list.h include/linux/list_bl.h include/linux/llist.h include/linux/log2.h include/linux/lsm_hook_defs.h include/linux/maple_tree.h include/linux/memcontrol.h include/linux/mempolicy.h include/linux/mm.h include/linux/mmzone.h include/linux/mount.h include/linux/nodemask.h include/linux/page-flags.h include/linux/page_ref.h include/linux/pagemap.h include/linux/perf_event.h include/linux/pgtable.h include/linux/pid.h include/linux/pm_qos.h include/linux/preempt.h include/linux/rbtree.h include/linux/rbtree_latch.h include/linux/rculist_bl.h include/linux/rcupdate.h include/linux/refcount.h include/linux/rmap.h include/linux/rtmutex.h include/linux/sched.h include/linux/sched/isolation.h include/linux/seqlock.h include/linux/spinlock_rt.h include/linux/srcu.h include/linux/swap.h include/linux/thread_info.h include/linux/timer.h include/linux/uaccess.h include/linux/ucopysize.h include/linux/userfaultfd_k.h include/linux/workqueue.h include/linux/xarray.h include/trace/events/exceptions.h include/trace/events/filemap.h include/trace/events/kmem.h include/trace/events/rpm.h include/trace/events/smbus.h include/trace/events/timer.h kernel/bpf/core.c kernel/cgroup/rstat.c kernel/kthread.c kernel/pid.c kernel/printk/printk_safe.c kernel/time/clockevents.c kernel/time/hrtimer.c kernel/time/posix-timers.c kernel/time/sleep_timeout.c kernel/time/tick-oneshot.c kernel/time/tick-sched.c kernel/time/time.c kernel/time/timekeeping.c kernel/time/timer.c lib/cpumask.c lib/errseq.c lib/idr.c lib/iomap.c lib/kobject.c lib/lockref.c lib/maple_tree.c lib/percpu_counter.c lib/radix-tree.c lib/strncpy_from_user.c lib/timerqueue.c lib/usercopy.c lib/vsprintf.c lib/xarray.c mm/backing-dev.c mm/fail_page_alloc.c mm/filemap.c mm/internal.h mm/list_lru.c mm/maccess.c mm/memory.c mm/mempolicy.c mm/mmap_lock.c mm/page_ext.c mm/page_owner.c mm/page_table_check.c mm/pgtable-generic.c mm/readahead.c mm/rmap.c mm/swap.c mm/swapfile.c security/device_cgroup.c security/integrity/ima/ima_main.c security/landlock/cred.h security/landlock/fs.c security/landlock/ruleset.c security/security.c security/smack/smack_access.c security/smack/smack_lsm.c security/tomoyo/audit.c security/tomoyo/common.c security/tomoyo/common.h security/tomoyo/domain.c security/tomoyo/file.c security/tomoyo/realpath.c security/tomoyo/tomoyo.c security/tomoyo/util.c usercopy_64.c]]
|
| 294/2 |
2026/07/30 13:06 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 111700
output: 23
thoughts: 1534
Thoughts: **USB Device ID Investigation: `au0828` Coverage**
Okay, so I'm trying to figure out why the `au0828` device isn't being covered by syzkaller, even though I've specified its Vendor ID (`0x2040`) and Product ID (`0x7200`). The initial assumption was that `syz_usb_connect` might be the culprit, as it's the syzkaller call I'm using to connect USB devices.
My first thought was that `syz_usb_connect` was modifying the `idVendor` and `idProduct` fields. I recalled that the `sys/linux/init_vusb.go` file (or `vusb.txt`) specifically mentions that the Go code patches these fields. I remembered `syz_usb_connect` patches these IDs to a specific list and, indeed, if I use `syz_usb_connect` alone with a basic `usb_device_descriptor`, it *would* overwrite my specified IDs.
However, I remembered that `syz_usb_connect` has variants. Specifically, the `$rtl8150` variant uses `usb_device_descriptor_rtl8150` which leverages `const` fields for `VENDOR` and `PRODUCT`, preventing patching. That's a good lead! Syzkaller doesn't patch `const` fields, which is perfect for forcing specific IDs.
But, a standard `usb_device_descriptor` struct uses `const[VENDOR, int16]` and `const[PRODUCT, int16]`. However, these are defined to `0` by default. And because syzkaller's Go code looks at the struct's definition to modify the IDs, I realised it's done during struct generation, not during execution. So if I pass a fully formed struct, it *shouldn't* be overwritten.
I considered passing a raw buffer to `syz_usb_connect` but, as expected, it complains about the argument type. I also went through and confirmed that the `$rtl8150` variant uses its own `VENDOR` and `PRODUCT` fields. But I'm targeting a different device.
So, I circled back to the fundamental point: If I use `syz_usb_connect` and provide `0x2040` and `0x7200` directly in the struct literal, will syzkaller overwrite it? The answer is *no*. `init_vusb.go` does its patching during generation or mutation, not during execution. If I provide a concrete program, it's executed *as is*. This means the ID's I provide should be used! So *why* is the `au0828` driver not probing?
It hit me, the problem wasn't the IDs! It's *what happens after* the USB device is connected. I re-examined the `au0828_usb_probe` function. I had set `bInterfaceNumber = 0`, and USB speed to high. Those were covered!
Therefore, the driver *is* probing! So what's wrong? The problem isn't with the IDs. I need to look at other failure points. The problem must be somewhere else in the driver probe function, or it might not be included in the kernel configuration.
|
| 295/2 |
2026/07/30 13:07 |
tool |
grepper |
0m
Args: map[Expression:CONFIG_VIDEO_AU0828]
Results: map[Output:drivers/media/usb/Makefile=24=obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
drivers/media/usb/Makefile:25:obj-$(CONFIG_VIDEO_AU0828) += au0828/
drivers/media/usb/Makefile-26-obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
--
drivers/media/usb/au0828/Makefile=2=au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
drivers/media/usb/au0828/Makefile-3-
drivers/media/usb/au0828/Makefile:4:ifeq ($(CONFIG_VIDEO_AU0828_V4L2),y)
drivers/media/usb/au0828/Makefile-5- au0828-objs += au0828-video.o au0828-vbi.o
drivers/media/usb/au0828/Makefile=6=endif
drivers/media/usb/au0828/Makefile-7-
drivers/media/usb/au0828/Makefile:8:ifeq ($(CONFIG_VIDEO_AU0828_RC),y)
drivers/media/usb/au0828/Makefile-9- au0828-objs += au0828-input.o
drivers/media/usb/au0828/Makefile=10=endif
drivers/media/usb/au0828/Makefile-11-
drivers/media/usb/au0828/Makefile:12:obj-$(CONFIG_VIDEO_AU0828) += au0828.o
drivers/media/usb/au0828/Makefile-13-
--
drivers/media/usb/au0828/au0828-cards.c=246=void au0828_card_analog_fe_setup(struct au0828_dev *dev)
drivers/media/usb/au0828/au0828-cards.c-247-{
drivers/media/usb/au0828/au0828-cards.c:248:#ifdef CONFIG_VIDEO_AU0828_V4L2
drivers/media/usb/au0828/au0828-cards.c-249- struct tuner_setup tun_setup;
--
drivers/media/usb/au0828/au0828-i2c.c=354=int au0828_i2c_register(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-i2c.c-368- dev->i2c_adap.algo_data = dev;
drivers/media/usb/au0828/au0828-i2c.c:369:#ifdef CONFIG_VIDEO_AU0828_V4L2
drivers/media/usb/au0828/au0828-i2c.c-370- i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
--
drivers/media/usb/au0828/au0828.h=173=struct au0828_dev {
--
drivers/media/usb/au0828/au0828.h-191-
drivers/media/usb/au0828/au0828.h:192:#ifdef CONFIG_VIDEO_AU0828_V4L2
drivers/media/usb/au0828/au0828.h-193- /* Analog */
--
drivers/media/usb/au0828/au0828.h-196-#endif
drivers/media/usb/au0828/au0828.h:197:#ifdef CONFIG_VIDEO_AU0828_RC
drivers/media/usb/au0828/au0828.h-198- struct au0828_rc *ir;
--
drivers/media/usb/au0828/au0828.h=322=extern void au0828_stop_vbi_streaming(struct vb2_queue *vq);
drivers/media/usb/au0828/au0828.h:323:#ifdef CONFIG_VIDEO_AU0828_V4L2
drivers/media/usb/au0828/au0828.h-324-extern int au0828_v4l2_device_register(struct usb_interface *interface,
--
drivers/media/usb/au0828/au0828.h=355=extern const struct vb2_ops au0828_vbi_qops;
--
drivers/media/usb/au0828/au0828.h-362-/* au0828-input.c */
drivers/media/usb/au0828/au0828.h:363:#ifdef CONFIG_VIDEO_AU0828_RC
drivers/media/usb/au0828/au0828.h-364-extern int au0828_rc_register(struct au0828_dev *dev);
]
|
| 296/2 |
2026/07/30 13:07 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 115354
output: 457
thoughts: 448
Thoughts: **Analyzing USB Driver Coverage in Syzbot**
Okay, so I need to figure out if the `CONFIG_VIDEO_AU0828` driver is actually enabled in syzbot. The easy way is usually to check if the corresponding source file, `drivers/media/usb/au0828/au0828-core.c`, got compiled. I could use `git-log` or `grepper` to look for "au0828" in the kernel config used by syzbot, but I don't have direct access to that.
Wait, the `au0828` driver is a media driver! Media drivers are generally enabled in syzbot as a rule. But... what if it *isn't* covered? Maybe it's NOT enabled. Let me go back and re-check `si4713` as a sanity check. Is *that* enabled? The relevant source would be `drivers/media/radio/si4713/radio-usb-si4713.c`. Okay, back to the main goal.
Now, if I use `syz_usb_connect` with `idVendor=0x10c4` and `idProduct=0x8244` and set `bInterfaceClass=3` (which is HID), will that work? Hmm, I couldn't set `bInterfaceClass=3` before because the `usb_interface_descriptor` was forcing `bInterfaceClass` to be zero! But... I *can* use `syz_usb_connect$hid`! That function uses `usb_device_descriptor_hid`. Okay, good.
Now, the `usb_device_descriptor_hid` definition has `VENDOR=0` and `PRODUCT=0`. So, if I use `syz_usb_connect$hid`, syzkaller patches the `VENDOR` and `PRODUCT` fields to random HID device values. But, hey, wait, can I just use the plain `syz_usb_connect` function and pass `ANY` for those values instead?
The thing is, `syz_usb_connect` takes a `dev` pointer, using `usb_device_descriptor` as its in parameter. Can I provide a raw byte array as the value of the device descriptor using something like `&AUTO="1201..."`? Let's give it a shot, that would be incredibly useful!
|
| 297/2 |
2026/07/30 13:07 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 18, &AUTO="\x12\x01\x00\x02\x00\x00\x00\x40\xc4\x10\x44\x82\x00\x00\x00\x00\x00\x01", 0)
r1 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r2 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r3 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r4 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r2, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 298/2 |
2026/07/30 13:07 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 116913
output: 430
thoughts: 83
Thoughts: Okay, here's my take on those thoughts, framed as my own mental processing:
**Debugging a Stubborn Data Type**
Ugh, "wrong string arg." Of course! This function expects a *struct*, not a plain string. Rookie mistake, but easily corrected. Hmm, how can I bypass this string requirement? That's it! I can use an `ANY` struct. This should be flexible enough to accommodate what I have. Let's try this hacky approach: `&AUTO=ANY=[@ANYBLOB="1201000200000040c4104482000000000001"]`. It will work!
|
| 299/2 |
2026/07/30 13:07 |
tool |
reproduce-crash |
2m
Args: map[ReproSyz:r0 = syz_usb_connect(3, 18, &AUTO=ANY=[@ANYBLOB="1201000200000040c4104482000000000001"], 0)
r1 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r2 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r3 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r4 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r2, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r3, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r4, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID:repro/c7e53a2b58119e9438a81744520064a9f96ef059 ReproducedBugTitle: ReproducedCrashReport:]
|
| 300/2 |
2026/07/30 13:09 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 117656
output: 61
thoughts: 14
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Coverage Check After Non-Crash**
Okay, so it didn't completely blow upβthat's a relief. But just because it didn't *crash* doesn't mean everything's peachy keen. My immediate thought is, "What's the coverage like?". A clean run doesn't necessarily mean a comprehensive one. I need to dig into the test coverage metrics, understand what code paths were actually exercised, and identify any gaps. Did we hit all the edge cases? Did the test suite execute the full range of expected behaviors? I'm not going to celebrate a successful run until I have a rock-solid understanding of what was and wasn't tested. I need to make sure we're not just dodging bullets; we're hitting our targets.
|
| 301/2 |
2026/07/30 13:09 |
tool |
get-coverage-files |
0m
Args: map[ExecutionCachedID:repro/c7e53a2b58119e9438a81744520064a9f96ef059]
Results: map[Files:[arch/x86/entry/vsyscall/vsyscall_64.c arch/x86/include/asm/atomic64_64.h arch/x86/include/asm/bitops.h arch/x86/include/asm/compat.h arch/x86/include/asm/cpufeature.h arch/x86/include/asm/irqflags.h arch/x86/include/asm/jump_label.h arch/x86/include/asm/mmu_context.h arch/x86/include/asm/page.h arch/x86/include/asm/pgtable.h arch/x86/include/asm/pkru.h arch/x86/include/asm/preempt.h arch/x86/kernel/cpu/aperfmperf.c arch/x86/kernel/fpu/context.h arch/x86/kernel/fpu/core.c arch/x86/kernel/kvm.c arch/x86/kernel/tsc.c arch/x86/mm/fault.c arch/x86/mm/maccess.c arch/x86/mm/pgtable.c arch/x86/pci/common.c arch/x86/pci/direct.c block/blk-cgroup.c drivers/acpi/acpica/nsaccess.c drivers/acpi/acpica/nsdump.c drivers/acpi/acpica/nssearch.c drivers/acpi/acpica/nsutils.c drivers/acpi/acpica/nsxfname.c drivers/acpi/acpica/utascii.c drivers/acpi/acpica/utdebug.c drivers/acpi/acpica/utmutex.c drivers/acpi/acpica/utstring.c drivers/acpi/device_pm.c drivers/acpi/osl.c drivers/acpi/property.c drivers/acpi/utils.c drivers/base/core.c drivers/base/map.c drivers/base/power/qos.c drivers/base/power/runtime.c drivers/base/power/wakeirq.c drivers/char/misc.c drivers/i2c/busses/i2c-i801.c drivers/i2c/i2c-core-base.c drivers/i2c/i2c-core-smbus.c drivers/i2c/i2c-core.h drivers/i2c/i2c-dev.c drivers/pci/access.c drivers/pci/ats.c drivers/pci/host-bridge.c drivers/pci/iov.c drivers/pci/msi/api.c drivers/pci/msi/msi.c drivers/pci/pci-acpi.c drivers/pci/pci-driver.c drivers/pci/pci.c drivers/pci/pcie/aer.c drivers/pci/pcie/aspm.c drivers/pci/quirks.c drivers/pci/rebar.c drivers/pci/vc.c drivers/usb/gadget/legacy/raw_gadget.c fs/char_dev.c fs/d_path.c fs/dcache.c fs/file.c fs/file_table.c fs/ioctl.c fs/libfs.c fs/mnt_idmapping.c fs/namei.c fs/namespace.c fs/notify/fsnotify.c fs/open.c include/acpi/acpi_bus.h include/asm-generic/bitops/instrumented-non-atomic.h include/asm-generic/pgalloc.h include/linux/atomic/atomic-arch-fallback.h include/linux/atomic/atomic-instrumented.h include/linux/atomic/atomic-long.h include/linux/audit.h include/linux/bit_spinlock.h include/linux/cgroup.h include/linux/clockchips.h include/linux/cpumask.h include/linux/cred.h include/linux/dcache.h include/linux/delayed_call.h include/linux/device.h include/linux/device_cgroup.h include/linux/err.h include/linux/file.h include/linux/file_ref.h include/linux/filelock.h include/linux/find.h include/linux/folio_batch.h include/linux/fs.h include/linux/fs/super.h include/linux/fsnotify.h include/linux/fsnotify_backend.h include/linux/hrtimer.h include/linux/jiffies.h include/linux/jump_label.h include/linux/kernel.h include/linux/kref.h include/linux/list.h include/linux/list_bl.h include/linux/llist.h include/linux/log2.h include/linux/lsm_hook_defs.h include/linux/maple_tree.h include/linux/memcontrol.h include/linux/mempolicy.h include/linux/mm.h include/linux/mmzone.h include/linux/mount.h include/linux/nodemask.h include/linux/page-flags.h include/linux/page_ref.h include/linux/pagemap.h include/linux/perf_event.h include/linux/pgtable.h include/linux/pid.h include/linux/pm_qos.h include/linux/preempt.h include/linux/rbtree.h include/linux/rbtree_latch.h include/linux/rculist_bl.h include/linux/rcupdate.h include/linux/refcount.h include/linux/rmap.h include/linux/rtmutex.h include/linux/sched.h include/linux/sched/isolation.h include/linux/seqlock.h include/linux/spinlock_rt.h include/linux/srcu.h include/linux/swap.h include/linux/thread_info.h include/linux/timer.h include/linux/uaccess.h include/linux/ucopysize.h include/linux/userfaultfd_k.h include/linux/vmstat.h include/linux/workqueue.h include/linux/xarray.h include/trace/events/exceptions.h include/trace/events/filemap.h include/trace/events/kmem.h include/trace/events/rpm.h include/trace/events/smbus.h include/trace/events/timer.h kernel/bpf/core.c kernel/cgroup/rstat.c kernel/kthread.c kernel/pid.c kernel/printk/printk_safe.c kernel/time/clockevents.c kernel/time/hrtimer.c kernel/time/posix-timers.c kernel/time/sleep_timeout.c kernel/time/tick-oneshot.c kernel/time/tick-sched.c kernel/time/time.c kernel/time/timekeeping.c kernel/time/timer.c lib/cpumask.c lib/errseq.c lib/idr.c lib/iomap.c lib/kobject.c lib/lockref.c lib/maple_tree.c lib/percpu_counter.c lib/plist.c lib/radix-tree.c lib/strncpy_from_user.c lib/timerqueue.c lib/usercopy.c lib/vsprintf.c lib/xarray.c mm/backing-dev.c mm/fail_page_alloc.c mm/filemap.c mm/internal.h mm/list_lru.c mm/maccess.c mm/memory.c mm/mempolicy.c mm/mmap_lock.c mm/page_counter.c mm/page_ext.c mm/page_owner.c mm/page_table_check.c mm/pgtable-generic.c mm/readahead.c mm/rmap.c mm/swap.c mm/swapfile.c security/device_cgroup.c security/integrity/ima/ima_main.c security/landlock/cred.h security/landlock/fs.c security/landlock/ruleset.c security/security.c security/smack/smack_access.c security/smack/smack_lsm.c security/tomoyo/audit.c security/tomoyo/common.c security/tomoyo/common.h security/tomoyo/domain.c security/tomoyo/file.c security/tomoyo/realpath.c security/tomoyo/tomoyo.c security/tomoyo/util.c usercopy_64.c]]
|
| 302/2 |
2026/07/30 13:09 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 120550
output: 736
thoughts: 1462
Thoughts: **USB Device Probe Troubleshooting**
Okay, so I'm still not seeing the `au0828` or `si4713` devices pop up. I tried using `syz_usb_connect` with `ANY`, but that didn't trigger them either. Why? Let's dig in. I know `syz_usb_connect` uses `raw_gadget`, and I confirmed that `raw_gadget` is covered, meaning the USB device is being *created*. But still no probe? It has to be the USB IDs.
I provided `0x2040` and `0x7200` in the `ANY` blob, so I need to check the exact contents. Let me see...
Okay, I'm looking at the hex dump of the blob now. Ah, there it is! I've confirmed that this *is* `si4713`, `0x10c4:0x8244`. But `si4713` needs `bDeviceClass = 0` and `bInterfaceClass = 3` (HID). The problem is, with `ANY` for `dev`, `syz_usb_connect` only overrides the `usb_device_descriptor`. What I need is the *entire* device configuration.
I remember now, `syz_usb_connect` takes `dev ptr[in, usb_device_descriptor]`, but it *expects* the `configs` array to be present *within* that `usb_device_descriptor` struct! Syzkaller defines the struct as, essentially, `usb_device_descriptor { inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]] } [packed]`. So, the `configs` array is *inlined*.
If I give it an `ANY` blob of only 18 bytes, which only represents the device descriptor, it *doesn't* include the configuration descriptors. This means `syz_usb_connect` sends a device descriptor of length 18, and *no* config descriptors! Then, `syz_usb_connect` reads from an empty `configs` array. No configurations mean no probes!
I need to give it the *full* blob, including the config, interface, and endpoint descriptors!
Okay, let's construct the complete blob for `si4713`.
* Device descriptor (18 bytes): `12 01 00 02 00 00 00 40 c4 10 44 82 00 00 00 00 00 01`
* Config descriptor (9 bytes): `09 02 22 00 01 01 00 80 00` (wTotalLength = 34, bNumInterfaces = 1)
* Interface descriptor (9 bytes): `09 04 00 00 01 03 00 00 00` (bInterfaceClass = 3 (HID), bNumEndpoints = 1)
* HID descriptor (9 bytes): `09 21 11 01 00 01 22 22 00` (bDescriptorType = 0x21 (HID), wDescriptorLength = 34)
* Endpoint descriptor (7 bytes): `07 05 81 03 40 00 01` (bEndpointAddress = 0x81 (IN), bmAttributes = 3 (Interrupt), wMaxPacketSize = 64, bInterval = 1)
`si4713` uses `USB_CLASS_HID`. I'll concatenate them:
* Device: `1201000200000040c4104482000000000001`
* Config: `090222000101008000`
* Interface: `090400000103000000`
* HID: `092111010001222200`
* Endpoint: `07058103400001`
Wait a minute, `wTotalLength` is `9 + 9 + 9 + 7 = 34` which is `0x
|
| 303/2 |
2026/07/30 13:10 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 52, &AUTO=ANY=[@ANYBLOB="1201000200000040c410448200000000000109022200010100800009040000010300000009211101000122220007058103400001"], 0)
syz_usb_control_io(r0, 0, &AUTO={AUTO, @generic={0x20, 0x01, AUTO, [0, 0, 0, 0, 0, 0, 0, 0]}})
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 304/2 |
2026/07/30 13:10 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 123868
output: 736
thoughts: 140
Thoughts: Here's my thought process, as it went down:
**Investigating the `vusb_responses` Structure**
Okay, so I'm looking at `vusb_responses`, and I'm realizing something immediately - there's no `@generic` *tag* defined. I was expecting a union with the `@generic` option, but it seems that's not the case. Let me double-check the definition of the `vusb_responses` struct itself.
Okay, here it is: `vusb_responses` has `len` (integer) and then `generic` which is a pointer to `vusb_response_generic`. The key thing to note is that `generic` is defined as a field of this struct, not an option within a union. It's a pointer to a struct.
Ah ha! So, the way this should be handled isn't a simple `@generic` reference within a union, itβs going to involve an `&AUTO` construct! Thinking about the expected usage, it's very likely that `generic` is going to be initialized with some default values. That means it needs to be `&AUTO={AUTO, &AUTO={0x20, 0x01, AUTO, [0, 0, 0, 0, 0, 0, 0, 0]}}` to make sure the field is properly allocated with some reasonable defaults. Let's try that and see if it works. I'm pretty confident that's the correct approach given the data layout.
|
| 305/2 |
2026/07/30 13:10 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 52, &AUTO=ANY=[@ANYBLOB="1201000200000040c410448200000000000109022200010100800009040000010300000009211101000122220007058103400001"], 0)
syz_usb_control_io(r0, 0, &AUTO={AUTO, &AUTO={0x20, 0x01, AUTO, [0, 0, 0, 0, 0, 0, 0, 0]}})
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 306/2 |
2026/07/30 13:10 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 125171
output: 745
thoughts: 195
Thoughts: **Debugging a Type Mismatch**
Okay, so I'm looking at this code and I see `data` is defined as an `array[int8, 0:256]`. But I'm getting a `wrong array arg *prog.BufferType` error, which makes me scratch my head. I know I've seen this pattern before, and I think it's clicking... wait, an `array[int8]` can often be *represented* as a string!
So, with that in mind, does `&AUTO={0x20, 0x01, AUTO, "0000000000000000"}` make sense here? I need to check the exact type...
Hold on, I see it now. The `data` variable within `vusb_response_generic` is indeed an `array[int8, 0:256]`. Knowing this, if it is treated as a generic `array[int8]`, I can utilize either an empty string `""` or something like `"\x00\x00..."` to initialize it. I think using an empty string or something like `"\x00\x00\x00\x00\x00\x00\x00\x00"` for empty data will be the cleanest approach.
|
| 307/2 |
2026/07/30 13:10 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 52, &AUTO=ANY=[@ANYBLOB="1201000200000040c410448200000000000109022200010100800009040000010300000009211101000122220007058103400001"], 0)
syz_usb_control_io(r0, 0, &AUTO={AUTO, &AUTO={0x20, 0x01, AUTO, "\x00\x00\x00\x00\x00\x00\x00\x00"}})
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 308/2 |
2026/07/30 13:10 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 126517
output: 730
thoughts: 252
Thoughts: **Debugging Syzkaller String Literals**
Okay, so I'm running into an issue with a null byte (`\x00`) in a string literal within syzkaller. Right, I remember that's generally not allowed unless I'm using a hex literal or properly escaping it. I thought I could use `[]` for arrays, and considered that as an option, but the error message, "wrong array arg *prog.BufferType," is throwing me off. `BufferType`...right, that implies it's expecting either a regular string or a hex literal. Okay, I've got a plan.
I think I can try constructing the value with the form `AUTO="0000000000000000"` or `&AUTO="0000000000000000"` to represent the value as a hex literal. But hold on... looking at the context, `data` is defined as `array[int8, 0:256]`. So, if it's treated as `array[int8]`, syzkaller expects a string or hex literal. The question is, can I just use an empty string, `""`? Or will that not work and do I need `&AUTO=""`? It's a field though. Since it's a field I should be able to just use `""` or the hex literal `"0000000000000000"`. I think the hex literal is the safest bet given the previous error. Okay, let's try `"0000000000000000"` and see if that resolves the issue!
|
| 309/2 |
2026/07/30 13:10 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, 52, &AUTO=ANY=[@ANYBLOB="1201000200000040c410448200000000000109022200010100800009040000010300000009211101000122220007058103400001"], 0)
syz_usb_control_io(r0, 0, &AUTO={AUTO, &AUTO={0x20, 0x01, AUTO, "0000000000000000"}})
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 310/2 |
2026/07/30 13:10 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 127969
output: 774
thoughts: 528
Thoughts: **Analyzing the `vusb_responses` Structure**
Okay, so I'm looking at this `vusb_responses` structure, and it's got way more fields than I initially accounted for. I only set up `len` and `generic` in my original setup. Now I see there are a bunch of other fields like `get_interface`, `get_configuration`, and a whole host of `asix_` related responses that I'm not directly using. The documentation and the code show seventeen fields in total.
Right, so to make this work, I need to make sure those remaining fields are initialized properly. Instead of having to define 0 for all those fields manually, I think I'll use the convenience of the `AUTO` macro and the syntax I know for setting everything else to zero. I think I can use `&AUTO={AUTO, &AUTO={0x20, 0x01, AUTO, "0000000000000000"}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}` to quickly address this. The first two auto fields handles `len` and `generic`, and then I will set 15 subsequent zeros to address the rest of the fields. That should take care of it and keep things clean.
|
| 311/2 |
2026/07/30 13:11 |
tool |
reproduce-crash |
2m
Args: map[ReproSyz:r0 = syz_usb_connect(3, 52, &AUTO=ANY=[@ANYBLOB="1201000200000040c410448200000000000109022200010100800009040000010300000009211101000122220007058103400001"], 0)
syz_usb_control_io(r0, 0, &AUTO={AUTO, &AUTO={0x20, 0x01, AUTO, "0000000000000000"}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
r1 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 0, 0)
r2 = syz_open_dev$video(&(0x7f0000000000)='/dev/video#\x00', 1, 0)
r3 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 0, 0)
r4 = syz_open_dev$radio(&(0x7f0000000000)='/dev/radio#\x00', 1, 0)
r5 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 0, 0)
r6 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 1, 0)
r7 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 2, 0)
r8 = syz_open_dev$I2C(&(0x7f0000000000)='/dev/i2c-#\x00', 3, 0)
syz_usb_disconnect(r0)
ioctl$I2C_SMBUS(r5, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r6, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r7, 0x720, &AUTO={0, 0, 0, 0})
ioctl$I2C_SMBUS(r8, 0x720, &AUTO={0, 0, 0, 0}) Sandbox:none]
Results: map[ExecutionCachedID:repro/ba2e75bc88e306a9def048b4fee6aae4a206c25a ReproducedBugTitle: ReproducedCrashReport:]
|
| 312/2 |
2026/07/30 13:13 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 129649
output: 55
thoughts: 12
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Initial Assessment and Verification**
Phew, that didn't go as expected; the system didn't crash. Good. My first instinct is to immediately shift focus to coverage. A successful execution is great, but without comprehensive test coverage, we're essentially flying blind. I need to know *how much* of the codebase this execution actually touched. A lack of crash doesn't guarantee correctness, only that we didn't trigger an immediate catastrophic failure. Now, let's drill down into the coverage reports. I want to see line-level detail, branches taken, and any gaps that might indicate untested code paths.
|
| 313/2 |
2026/07/30 13:13 |
tool |
get-coverage-files |
0m
Args: map[ExecutionCachedID:repro/ba2e75bc88e306a9def048b4fee6aae4a206c25a]
Results: map[Files:[arch/x86/entry/vsyscall/vsyscall_64.c arch/x86/include/asm/atomic.h arch/x86/include/asm/atomic64_64.h arch/x86/include/asm/bitops.h arch/x86/include/asm/compat.h arch/x86/include/asm/cpufeature.h arch/x86/include/asm/irqflags.h arch/x86/include/asm/jump_label.h arch/x86/include/asm/mmu_context.h arch/x86/include/asm/page.h arch/x86/include/asm/pgtable.h arch/x86/include/asm/pkru.h arch/x86/include/asm/preempt.h arch/x86/include/asm/trace/fpu.h arch/x86/kernel/cpu/aperfmperf.c arch/x86/kernel/fpu/context.h arch/x86/kernel/fpu/core.c arch/x86/kernel/fpu/internal.h arch/x86/kernel/fpu/xstate.c arch/x86/kernel/kvm.c arch/x86/kernel/tsc.c arch/x86/mm/fault.c arch/x86/mm/maccess.c arch/x86/mm/pgtable.c arch/x86/pci/common.c arch/x86/pci/direct.c block/blk-cgroup.c drivers/acpi/acpica/nsaccess.c drivers/acpi/acpica/nsdump.c drivers/acpi/acpica/nssearch.c drivers/acpi/acpica/nsutils.c drivers/acpi/acpica/nsxfname.c drivers/acpi/acpica/utascii.c drivers/acpi/acpica/utdebug.c drivers/acpi/acpica/utmutex.c drivers/acpi/acpica/utstring.c drivers/acpi/device_pm.c drivers/acpi/glue.c drivers/acpi/osl.c drivers/acpi/property.c drivers/acpi/utils.c drivers/base/base.h drivers/base/bus.c drivers/base/class.c drivers/base/core.c drivers/base/dd.c drivers/base/devres.c drivers/base/devtmpfs.c drivers/base/driver.c drivers/base/map.c drivers/base/module.c drivers/base/physical_location.c drivers/base/power/common.c drivers/base/power/main.c drivers/base/power/power.h drivers/base/power/qos.c drivers/base/power/runtime.c drivers/base/power/sysfs.c drivers/base/power/wakeirq.c drivers/base/power/wakeup.c drivers/base/power/wakeup_stats.c drivers/base/property.c drivers/base/swnode.c drivers/char/misc.c drivers/gpu/drm/drm_sysfs.c drivers/hid/hid-core.c drivers/hid/hid-quirks.c drivers/hid/usbhid/hid-core.c drivers/i2c/busses/i2c-i801.c drivers/i2c/i2c-core-base.c drivers/i2c/i2c-core-smbus.c drivers/i2c/i2c-core.h drivers/i2c/i2c-dev.c drivers/media/common/videobuf2/videobuf2-core.c drivers/media/common/videobuf2/videobuf2-v4l2.c drivers/media/mc/mc-request.c drivers/media/radio/si4713/radio-usb-si4713.c drivers/media/test-drivers/vicodec/codec-v4l2-fwht.c drivers/media/test-drivers/vicodec/vicodec-core.c drivers/media/v4l2-core/v4l2-ctrls-core.c drivers/media/v4l2-core/v4l2-ctrls-defs.c drivers/media/v4l2-core/v4l2-ctrls-request.c drivers/media/v4l2-core/v4l2-dev.c drivers/media/v4l2-core/v4l2-fh.c drivers/media/v4l2-core/v4l2-mem2mem.c drivers/of/base.c drivers/of/device.c drivers/pci/access.c drivers/pci/ats.c drivers/pci/host-bridge.c drivers/pci/iov.c drivers/pci/msi/api.c drivers/pci/msi/msi.c drivers/pci/pci-acpi.c drivers/pci/pci-driver.c drivers/pci/pci.c drivers/pci/pcie/aer.c drivers/pci/pcie/aspm.c drivers/pci/quirks.c drivers/pci/rebar.c drivers/pci/vc.c drivers/thunderbolt/acpi.c drivers/usb/common/common.c drivers/usb/core/config.c drivers/usb/core/devio.c drivers/usb/core/driver.c drivers/usb/core/endpoint.c drivers/usb/core/generic.c drivers/usb/core/hcd.c drivers/usb/core/hub.c drivers/usb/core/hub.h drivers/usb/core/message.c drivers/usb/core/notify.c drivers/usb/core/of.c drivers/usb/core/quirks.c drivers/usb/core/sysfs.c drivers/usb/core/trace.h drivers/usb/core/urb.c drivers/usb/core/usb-acpi.c drivers/usb/core/usb.c drivers/usb/core/usb.h drivers/usb/gadget/legacy/raw_gadget.c drivers/usb/gadget/udc/core.c drivers/usb/gadget/udc/dummy_hcd.c drivers/usb/gadget/udc/trace.h drivers/usb/misc/usbtest.c drivers/usb/mon/mon_main.c fs/char_dev.c fs/d_path.c fs/dcache.c fs/eventpoll.c fs/fcntl.c fs/file.c fs/file_table.c fs/inode.c fs/internal.h fs/ioctl.c fs/kernfs/dir.c fs/kernfs/file.c fs/kernfs/kernfs-internal.h fs/kernfs/symlink.c fs/libfs.c fs/locks.c fs/mnt_idmapping.c fs/namei.c fs/namespace.c fs/notify/dnotify/dnotify.c fs/notify/fsnotify.c fs/open.c fs/sysfs/dir.c fs/sysfs/file.c fs/sysfs/group.c fs/sysfs/symlink.c include/acpi/acpi_bus.h include/asm-generic/bitops/instrumented-non-atomic.h include/asm-generic/pgalloc.h include/asm-generic/sections.h include/linux/acpi.h include/linux/async.h include/linux/atomic/atomic-arch-fallback.h include/linux/atomic/atomic-instrumented.h include/linux/atomic/atomic-long.h include/linux/audit.h include/linux/bit_spinlock.h include/linux/cgroup.h include/linux/clockchips.h include/linux/cpumask.h include/linux/cred.h include/linux/ctype.h include/linux/dcache.h include/linux/delayed_call.h include/linux/device.h include/linux/device_cgroup.h include/linux/err.h include/linux/eventpoll.h include/linux/file.h include/linux/file_ref.h include/linux/filelock.h include/linux/filter.h include/linux/find.h include/linux/folio_batch.h include/linux/fortify-string.h include/linux/fs.h include/linux/fs/super.h include/linux/fsnotify.h include/linux/fsnotify_backend.h include/linux/hrtimer.h include/linux/idr.h include/linux/instrumented.h include/linux/jiffies.h include/linux/jump_label.h include/linux/kcov.h include/linux/kernel.h include/linux/kernfs.h include/linux/kobject.h include/linux/kref.h include/linux/kthread.h include/linux/list.h include/linux/list_bl.h include/linux/llist.h include/linux/log2.h include/linux/lsm_hook_defs.h include/linux/maple_tree.h include/linux/memcontrol.h include/linux/mempolicy.h include/linux/mm.h include/linux/mmzone.h include/linux/mount.h include/linux/netfilter/nf_conntrack_common.h include/linux/nodemask.h include/linux/of.h include/linux/page-flags.h include/linux/page_ext.h include/linux/page_ref.h include/linux/pagemap.h include/linux/perf_event.h include/linux/pgtable.h include/linux/pid.h include/linux/pm_qos.h include/linux/pm_runtime.h include/linux/preempt.h include/linux/rbtree.h include/linux/rbtree_latch.h include/linux/rculist_bl.h include/linux/rcupdate.h include/linux/refcount.h include/linux/rmap.h include/linux/rtmutex.h include/linux/sched.h include/linux/sched/isolation.h include/linux/seqlock.h include/linux/skbuff.h include/linux/slab.h include/linux/spinlock_rt.h include/linux/srcu.h include/linux/swap.h include/linux/thread_info.h include/linux/timer.h include/linux/uaccess.h include/linux/ucopysize.h include/linux/usb.h include/linux/usb/gadget.h include/linux/usb/hcd.h include/linux/userfaultfd_k.h include/linux/vmstat.h include/linux/wait.h include/linux/workqueue.h include/linux/xarray.h include/net/dst.h include/net/netns/generic.h include/net/sock.h include/trace/events/csd.h include/trace/events/exceptions.h include/trace/events/filemap.h include/trace/events/ipi.h include/trace/events/kmem.h include/trace/events/notifier.h include/trace/events/printk.h include/trace/events/rpm.h include/trace/events/skb.h include/trace/events/smbus.h include/trace/events/sock.h include/trace/events/timer.h include/trace/events/workqueue.h include/uapi/linux/usb/ch9.h kernel/bpf/core.c kernel/cgroup/rstat.c kernel/dma/swiotlb.c kernel/irq_work.c kernel/kthread.c kernel/notifier.c kernel/panic.c kernel/params.c kernel/pid.c kernel/printk/internal.h kernel/printk/nbcon.c kernel/printk/printk.c kernel/printk/printk_ringbuffer.c kernel/printk/printk_safe.c kernel/smp.c kernel/time/clockevents.c kernel/time/hrtimer.c kernel/time/posix-timers.c kernel/time/sleep_timeout.c kernel/time/tick-oneshot.c kernel/time/tick-sched.c kernel/time/time.c kernel/time/timekeeping.c kernel/time/timer.c kernel/workqueue.c lib/cmdline.c lib/cpumask.c lib/errseq.c lib/idr.c lib/iomap.c lib/kasprintf.c lib/klist.c lib/kobject.c lib/kobject_uevent.c lib/kstrtox.c lib/lockref.c lib/maple_tree.c lib/percpu_counter.c lib/plist.c lib/radix-tree.c lib/strncpy_from_user.c lib/timerqueue.c lib/usercopy.c lib/vsprintf.c lib/xarray.c mm/backing-dev.c mm/fail_page_alloc.c mm/filemap.c mm/internal.h mm/list_lru.c mm/maccess.c mm/memory.c mm/mempolicy.c mm/mmap_lock.c mm/page_counter.c mm/page_ext.c mm/page_owner.c mm/page_table_check.c mm/percpu.c mm/pgtable-generic.c mm/readahead.c mm/rmap.c mm/swap.c mm/swapfile.c mm/util.c mm/vmalloc.c net/core/filter.c net/core/skbuff.c net/core/sock.c net/netlink/af_netlink.c security/device_cgroup.c security/integrity/evm/evm.h security/integrity/evm/evm_main.c security/integrity/ima/ima_main.c security/landlock/cred.h security/landlock/fs.c security/landlock/ruleset.c security/security.c security/smack/smack_access.c security/smack/smack_lsm.c security/tomoyo/audit.c security/tomoyo/common.c security/tomoyo/common.h security/tomoyo/domain.c security/tomoyo/file.c security/tomoyo/realpath.c security/tomoyo/tomoyo.c security/tomoyo/util.c usercopy_64.c]]
|
| 314/2 |
2026/07/30 13:13 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 134256
output: 86
thoughts: 107
Thoughts: Here's my thought process, as if I were reviewing this:
**Initial Assessment of Driver Availability**
Okay, still no sign of the `si4713` or `au0828` modules... which is expected, but I need to make sure. Wait a minute! Hang on... the coverage report *does* include `drivers/media/radio/si4713/radio-usb-si4713.c`! Excellent! That's a key piece of good news. I need to make sure I am reading this right. Alright, this is what I thought, `drivers/media/radio/si4713/radio-usb-si4713.c` *is* actually present in the coverage data. Now I need to drill down and review the coverage for that specific file. Let's see how well it's been tested. That's the next step.
|
| 315/2 |
2026/07/30 13:13 |
tool |
get-file-coverage |
0m
Args: map[ExecutionCachedID:repro/ba2e75bc88e306a9def048b4fee6aae4a206c25a Filename:drivers/media/radio/si4713/radio-usb-si4713.c Functions:[]]
Results: map[CoveredFunctions:[si4713_send_startup_command si4713_start_seq usb_si4713_probe] Snippets:[Function: si4713_send_startup_command
1: // SPDX-License-Identifier: GPL-2.0-only
2: /*
3: * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
4: * All rights reserved.
5: */
6:
7: /* kernel includes */
8: #include <linux/kernel.h>
9: #include <linux/module.h>
10: #include <linux/usb.h>
11: #include <linux/init.h>
12: #include <linux/slab.h>
13: #include <linux/input.h>
14: #include <linux/mutex.h>
15: #include <linux/i2c.h>
16: /* V4l includes */
17: #include <linux/videodev2.h>
18: #include <media/v4l2-common.h>
19: #include <media/v4l2-device.h>
20: #include <media/v4l2-ioctl.h>
21: #include <media/v4l2-event.h>
22: #include <linux/platform_data/media/si4713.h>
23:
24: #include "si4713.h"
25:
26: /* driver and module definitions */
27: MODULE_AUTHOR("Dinesh Ram <dinesh.ram@cern.ch>");
28: MODULE_DESCRIPTION("Si4713 FM Transmitter USB driver");
29: MODULE_LICENSE("GPL v2");
30:
31: /* The Device announces itself as Cygnal Integrated Products, Inc. */
32: #define USB_SI4713_VENDOR 0x10c4
33: #define USB_SI4713_PRODUCT 0x8244
34:
35: #define BUFFER_LENGTH 64
36: #define USB_TIMEOUT 1000
37: #define USB_RESP_TIMEOUT 50000
38:
39: /* USB Device ID List */
40: static const struct usb_device_id usb_si4713_usb_device_table[] = {
41: {USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT,
42: USB_CLASS_HID, 0, 0) },
43: { } /* Terminating entry */
44: };
45:
46: MODULE_DEVICE_TABLE(usb, usb_si4713_usb_device_table);
47:
48: struct si4713_usb_device {
49: struct usb_device *usbdev;
50: struct usb_interface *intf;
51: struct video_device vdev;
52: struct v4l2_device v4l2_dev;
53: struct v4l2_subdev *v4l2_subdev;
54: struct mutex lock;
55: struct i2c_adapter i2c_adapter;
56:
57: u8 *buffer;
58: };
59:
60: static inline struct si4713_usb_device *to_si4713_dev(struct v4l2_device *v4l2_dev)
61: {
62: return container_of(v4l2_dev, struct si4713_usb_device, v4l2_dev);
63: }
64:
65: static int vidioc_querycap(struct file *file, void *priv,
66: struct v4l2_capability *v)
67: {
68: struct si4713_usb_device *radio = video_drvdata(file);
69:
70: strscpy(v->driver, "radio-usb-si4713", sizeof(v->driver));
71: strscpy(v->card, "Si4713 FM Transmitter", sizeof(v->card));
72: usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
73: return 0;
74: }
75:
76: static int vidioc_g_modulator(struct file *file, void *priv,
77: struct v4l2_modulator *vm)
78: {
79: struct si4713_usb_device *radio = video_drvdata(file);
80:
81: return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_modulator, vm);
82: }
83:
84: static int vidioc_s_modulator(struct file *file, void *priv,
85: const struct v4l2_modulator *vm)
86: {
87: struct si4713_usb_device *radio = video_drvdata(file);
88:
89: return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_modulator, vm);
90: }
91:
92: static int vidioc_s_frequency(struct file *file, void *priv,
93: const struct v4l2_frequency *vf)
94: {
95: struct si4713_usb_device *radio = video_drvdata(file);
96:
97: return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_frequency, vf);
98: }
99:
100: static int vidioc_g_frequency(struct file *file, void *priv,
101: struct v4l2_frequency *vf)
102: {
103: struct si4713_usb_device *radio = video_drvdata(file);
104:
105: return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_frequency, vf);
106: }
107:
108: static const struct v4l2_ioctl_ops usb_si4713_ioctl_ops = {
109: .vidioc_querycap = vidioc_querycap,
110: .vidioc_g_modulator = vidioc_g_modulator,
111: .vidioc_s_modulator = vidioc_s_modulator,
112: .vidioc_g_frequency = vidioc_g_frequency,
113: .vidioc_s_frequency = vidioc_s_frequency,
114: .vidioc_log_status = v4l2_ctrl_log_status,
115: .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
116: .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
117: };
118:
119: /* File system interface */
120: static const struct v4l2_file_operations usb_si4713_fops = {
121: .owner = THIS_MODULE,
122: .open = v4l2_fh_open,
123: .release = v4l2_fh_release,
124: .poll = v4l2_ctrl_poll,
125: .unlocked_ioctl = video_ioctl2,
126: };
127:
128: static void usb_si4713_video_device_release(struct v4l2_device *v4l2_dev)
129: {
130: struct si4713_usb_device *radio = to_si4713_dev(v4l2_dev);
131: struct i2c_adapter *adapter = &radio->i2c_adapter;
132:
133: i2c_del_adapter(adapter);
134: v4l2_device_unregister(&radio->v4l2_dev);
135: kfree(radio->buffer);
136: kfree(radio);
137: }
138:
139: /*
140: * This command sequence emulates the behaviour of the Windows driver.
141: * The structure of these commands was determined by sniffing the
142: * usb traffic of the device during startup.
143: * Most likely, these commands make some queries to the device.
144: * Commands are sent to enquire parameters like the bus mode,
145: * component revision, boot mode, the device serial number etc.
146: *
147: * These commands are necessary to be sent in this order during startup.
148: * The device fails to powerup if these commands are not sent.
149: *
150: * The complete list of startup commands is given in the start_seq table below.
151: */
152: static int si4713_send_startup_command(struct si4713_usb_device *radio)
153: {
154: unsigned long until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1;
155: u8 *buffer = radio->buffer;
156: int retval;
157:
158: /* send the command */
159: retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
160: 0x09, 0x21, 0x033f, 0, radio->buffer,
161: BUFFER_LENGTH, USB_TIMEOUT);
* 162: if (retval < 0)
163: return retval;
164:
165: for (;;) {
166: /* receive the response */
167: retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
168: 0x01, 0xa1, 0x033f, 0, radio->buffer,
169: BUFFER_LENGTH, USB_TIMEOUT);
170: if (retval < 0)
171: return retval;
172: if (!radio->buffer[1]) {
Function: si4713_start_seq
237: { 6, { 0x06, 0x03, 0x03, 0x08, 0x01, 0x0f } },
238: };
239:
240: static int si4713_start_seq(struct si4713_usb_device *radio)
241: {
242: int retval = 0;
243: int i;
244:
245: radio->buffer[0] = 0x3f;
246:
* 247: for (i = 0; i < ARRAY_SIZE(start_seq); i++) {
248: int len = start_seq[i].len;
249: const u8 *payload = start_seq[i].payload;
250:
251: memcpy(radio->buffer + 1, payload, len);
252: memset(radio->buffer + len + 1, 0, BUFFER_LENGTH - 1 - len);
* 253: retval = si4713_send_startup_command(radio);
254: }
255:
256: return retval;
257: }
258:
259: static struct i2c_board_info si4713_board_info = {
260: I2C_BOARD_INFO("si4713", SI4713_I2C_ADDR_BUSEN_HIGH),
261: };
262:
263: struct si4713_command_table {
Function: usb_si4713_probe
403: /* set up sysfs linkage to our parent device */
404: radio->i2c_adapter.dev.parent = &radio->usbdev->dev;
405: i2c_set_adapdata(&radio->i2c_adapter, radio);
406:
407: return i2c_add_adapter(&radio->i2c_adapter);
408: }
409:
410: /* check if the device is present and register with v4l and usb if it is */
411: static int usb_si4713_probe(struct usb_interface *intf,
412: const struct usb_device_id *id)
* 413: {
414: struct si4713_usb_device *radio;
415: struct i2c_adapter *adapter;
416: struct v4l2_subdev *sd;
417: int retval;
418:
419: dev_info(&intf->dev, "Si4713 development board discovered: (%04X:%04X)\n",
420: id->idVendor, id->idProduct);
421:
422: /* Initialize local device structure */
423: radio = kzalloc_obj(struct si4713_usb_device);
424: if (radio)
425: radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
426:
427: if (!radio || !radio->buffer) {
428: dev_err(&intf->dev, "kmalloc for si4713_usb_device failed\n");
429: kfree(radio);
430: return -ENOMEM;
431: }
432:
433: mutex_init(&radio->lock);
434:
435: radio->usbdev = interface_to_usbdev(intf);
436: radio->intf = intf;
437: usb_set_intfdata(intf, &radio->v4l2_dev);
438:
* 439: retval = si4713_start_seq(radio);
* 440: if (retval < 0)
441: goto err_v4l2;
442:
443: retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
444: if (retval < 0) {
445: dev_err(&intf->dev, "couldn't register v4l2_device\n");
446: goto err_v4l2;
447: }
448:
449: retval = si4713_register_i2c_adapter(radio);
450: if (retval < 0) {
]]
|
| 316/2 |
2026/07/30 13:13 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 138941
output: 99
thoughts: 719
Thoughts: **Debugging the SI4713 USB Probe**
Okay, so `usb_si4713_probe` is triggered, which means we're in the right place. Then, `si4713_start_seq` and `si4713_send_startup_command` are called, as expected. But then, `usb_control_msg` returns a negative value. Why? The original hunch was that `syz_usb_connect` doesn't handle vendor-specific control messages.
Let's break down `si4713_send_startup_command`. It's sending a `usb_control_msg` with `bRequest = 0x09` (SET_REPORT) and `bRequestType = 0x21` (OUT, CLASS, INTERFACE). Initially, I thought that `syz_usb_control_io` couldn't handle this as I was providing a GET_REPORT request, but then I realized that `syz_usb_control_io` *can* respond to this! It's just that I was only looking at the IN requests, not the OUT requests. In fact, syzkaller *accepts* OUT requests automatically!
So, the mystery is *why* did `usb_control_msg` return a negative value? It should have just succeeded. Rechecking the coverage output, it looks like line 162 is covered, but line 163 (the `return` statement after the error check) is *not*. This means `retval` is not less than 0. The first call to `usb_control_msg` *succeeded*!
This points to the loop that comes next:
```
165: for (;;) {
166: /* receive the response */
167: retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
168: 0x01, 0xa1, 0x033f, 0, radio->buffer,
169: BUFFER_LENGTH, USB_TIMEOUT);
170: if (retval < 0)
171: return retval;
```
That entire block (lines 165-172) is NOT in the coverage report. This is where the issue must lie. I need full coverage for `si4713_send_startup_command` to see what is going on with the second `usb_control_msg` call.
|
| 317/2 |
2026/07/30 13:13 |
tool |
get-file-coverage |
0m
Args: map[ExecutionCachedID:repro/ba2e75bc88e306a9def048b4fee6aae4a206c25a Filename:drivers/media/radio/si4713/radio-usb-si4713.c Functions:[si4713_send_startup_command]]
Results: map[CoveredFunctions:[si4713_send_startup_command si4713_start_seq usb_si4713_probe] Snippets:[Function: si4713_send_startup_command
1: // SPDX-License-Identifier: GPL-2.0-only
2: /*
3: * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
4: * All rights reserved.
5: */
6:
7: /* kernel includes */
8: #include <linux/kernel.h>
9: #include <linux/module.h>
10: #include <linux/usb.h>
11: #include <linux/init.h>
12: #include <linux/slab.h>
13: #include <linux/input.h>
14: #include <linux/mutex.h>
15: #include <linux/i2c.h>
16: /* V4l includes */
17: #include <linux/videodev2.h>
18: #include <media/v4l2-common.h>
19: #include <media/v4l2-device.h>
20: #include <media/v4l2-ioctl.h>
21: #include <media/v4l2-event.h>
22: #include <linux/platform_data/media/si4713.h>
23:
24: #include "si4713.h"
25:
26: /* driver and module definitions */
27: MODULE_AUTHOR("Dinesh Ram <dinesh.ram@cern.ch>");
28: MODULE_DESCRIPTION("Si4713 FM Transmitter USB driver");
29: MODULE_LICENSE("GPL v2");
30:
31: /* The Device announces itself as Cygnal Integrated Products, Inc. */
32: #define USB_SI4713_VENDOR 0x10c4
33: #define USB_SI4713_PRODUCT 0x8244
34:
35: #define BUFFER_LENGTH 64
36: #define USB_TIMEOUT 1000
37: #define USB_RESP_TIMEOUT 50000
38:
39: /* USB Device ID List */
40: static const struct usb_device_id usb_si4713_usb_device_table[] = {
41: {USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT,
42: USB_CLASS_HID, 0, 0) },
43: { } /* Terminating entry */
44: };
45:
46: MODULE_DEVICE_TABLE(usb, usb_si4713_usb_device_table);
47:
48: struct si4713_usb_device {
49: struct usb_device *usbdev;
50: struct usb_interface *intf;
51: struct video_device vdev;
52: struct v4l2_device v4l2_dev;
53: struct v4l2_subdev *v4l2_subdev;
54: struct mutex lock;
55: struct i2c_adapter i2c_adapter;
56:
57: u8 *buffer;
58: };
59:
60: static inline struct si4713_usb_device *to_si4713_dev(struct v4l2_device *v4l2_dev)
61: {
62: return container_of(v4l2_dev, struct si4713_usb_device, v4l2_dev);
63: }
64:
65: static int vidioc_querycap(struct file *file, void *priv,
66: struct v4l2_capability *v)
67: {
68: struct si4713_usb_device *radio = video_drvdata(file);
69:
70: strscpy(v->driver, "radio-usb-si4713", sizeof(v->driver));
71: strscpy(v->card, "Si4713 FM Transmitter", sizeof(v->card));
72: usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
73: return 0;
74: }
75:
76: static int vidioc_g_modulator(struct file *file, void *priv,
77: struct v4l2_modulator *vm)
78: {
79: struct si4713_usb_device *radio = video_drvdata(file);
80:
81: return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_modulator, vm);
82: }
83:
84: static int vidioc_s_modulator(struct file *file, void *priv,
85: const struct v4l2_modulator *vm)
86: {
87: struct si4713_usb_device *radio = video_drvdata(file);
88:
89: return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_modulator, vm);
90: }
91:
92: static int vidioc_s_frequency(struct file *file, void *priv,
93: const struct v4l2_frequency *vf)
94: {
95: struct si4713_usb_device *radio = video_drvdata(file);
96:
97: return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_frequency, vf);
98: }
99:
100: static int vidioc_g_frequency(struct file *file, void *priv,
101: struct v4l2_frequency *vf)
102: {
103: struct si4713_usb_device *radio = video_drvdata(file);
104:
105: return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_frequency, vf);
106: }
107:
108: static const struct v4l2_ioctl_ops usb_si4713_ioctl_ops = {
109: .vidioc_querycap = vidioc_querycap,
110: .vidioc_g_modulator = vidioc_g_modulator,
111: .vidioc_s_modulator = vidioc_s_modulator,
112: .vidioc_g_frequency = vidioc_g_frequency,
113: .vidioc_s_frequency = vidioc_s_frequency,
114: .vidioc_log_status = v4l2_ctrl_log_status,
115: .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
116: .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
117: };
118:
119: /* File system interface */
120: static const struct v4l2_file_operations usb_si4713_fops = {
121: .owner = THIS_MODULE,
122: .open = v4l2_fh_open,
123: .release = v4l2_fh_release,
124: .poll = v4l2_ctrl_poll,
125: .unlocked_ioctl = video_ioctl2,
126: };
127:
128: static void usb_si4713_video_device_release(struct v4l2_device *v4l2_dev)
129: {
130: struct si4713_usb_device *radio = to_si4713_dev(v4l2_dev);
131: struct i2c_adapter *adapter = &radio->i2c_adapter;
132:
133: i2c_del_adapter(adapter);
134: v4l2_device_unregister(&radio->v4l2_dev);
135: kfree(radio->buffer);
136: kfree(radio);
137: }
138:
139: /*
140: * This command sequence emulates the behaviour of the Windows driver.
141: * The structure of these commands was determined by sniffing the
142: * usb traffic of the device during startup.
143: * Most likely, these commands make some queries to the device.
144: * Commands are sent to enquire parameters like the bus mode,
145: * component revision, boot mode, the device serial number etc.
146: *
147: * These commands are necessary to be sent in this order during startup.
148: * The device fails to powerup if these commands are not sent.
149: *
150: * The complete list of startup commands is given in the start_seq table below.
151: */
152: static int si4713_send_startup_command(struct si4713_usb_device *radio)
153: {
154: unsigned long until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1;
155: u8 *buffer = radio->buffer;
156: int retval;
157:
158: /* send the command */
159: retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
160: 0x09, 0x21, 0x033f, 0, radio->buffer,
161: BUFFER_LENGTH, USB_TIMEOUT);
* 162: if (retval < 0)
163: return retval;
164:
165: for (;;) {
166: /* receive the response */
167: retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
168: 0x01, 0xa1, 0x033f, 0, radio->buffer,
169: BUFFER_LENGTH, USB_TIMEOUT);
170: if (retval < 0)
171: return retval;
172: if (!radio->buffer[1]) {
]]
|
| 318/2 |
2026/07/30 13:13 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 143317
output: 32
thoughts: 2285
Thoughts: **Analyzing a USB Driver UAF Bug**
Okay, so I'm diving into this issue. First, I noticed some lines in the code that weren't being hit during execution - lines 163 and 165, specifically. Then I started tracing through the flow, thinking the `usb_control_msg` might be the problem, perhaps blocking or crashing. But it must have returned, and now that I think about it, the issue doesn't appear to be related to the `usb_control_msg` returning or crashing, because the code seems to check the return value correctly. I checked the coverage of `si4713_start_seq` and realized it was returning an error without breaking.
After checking the code for error handling, I realized that if the `si4713_send_startup_command` function returns an error, the error code would be returned by `si4713_start_seq`. This happens if `usb_control_msg` returns an error, such as a timeout or STALL signal which can be mapped to `-EPIPE`. This means `usb_si4713_probe` will fail, and the I2C adapter will not be registered, and as a result, this driver isn't the cause of the bug.
I then went back to the bug report to analyze the stack trace and allocation information and noticed the key traces. I focused on the allocation stack and the reported allocation size (4096 bytes, within `kmalloc-4k`). I initially thought the UAF was on an environment variable buffer allocated by `kobject_uevent_env` but then realized that the reported UAF occurs through a `struct device` pointer, specifically accessing its `type` member, so the bug isn't in that buffer. I checked the size of `struct kobj_uevent_env`, which is around 2048 bytes, and I then considered that the bug is on `struct usb_device`, which is allocated in the `kmalloc-4k` pool.
If this were the case, the memory of the `struct usb_device` would be freed, and then, later, re-allocated. The allocation stack is the last one that happened to land on this block of memory.
I need to understand what else in that driver could be causing this. Time to dig further.
|
| 319/2 |
2026/07/30 13:14 |
tool |
grepper |
0m
Args: map[Expression:i2c_add_adapter PathPrefix:drivers/media/usb]
Results: map[Output:drivers/media/usb/au0828/au0828-i2c.c=354=int au0828_i2c_register(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-i2c.c-373-#endif
drivers/media/usb/au0828/au0828-i2c.c:374: i2c_add_adapter(&dev->i2c_adap);
drivers/media/usb/au0828/au0828-i2c.c-375-
--
drivers/media/usb/cx231xx/cx231xx-i2c.c=514=int cx231xx_i2c_register(struct cx231xx_i2c *bus)
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-527- i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
drivers/media/usb/cx231xx/cx231xx-i2c.c:528: bus->i2c_rc = i2c_add_adapter(&bus->i2c_adap);
drivers/media/usb/cx231xx/cx231xx-i2c.c-529-
--
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c=56=static int dvb_usbv2_i2c_init(struct dvb_usb_device *d)
--
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c-68-
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c:69: ret = i2c_add_adapter(&d->i2c_adap);
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c-70- if (ret < 0) {
--
drivers/media/usb/dvb-usb/dvb-usb-i2c.c=11=int dvb_usb_i2c_init(struct dvb_usb_device *d)
--
drivers/media/usb/dvb-usb/dvb-usb-i2c.c-30-
drivers/media/usb/dvb-usb/dvb-usb-i2c.c:31: ret = i2c_add_adapter(&d->i2c_adap);
drivers/media/usb/dvb-usb/dvb-usb-i2c.c-32- if (ret < 0) {
--
drivers/media/usb/em28xx/em28xx-i2c.c=970=int em28xx_i2c_register(struct em28xx *dev, unsigned int bus,
--
drivers/media/usb/em28xx/em28xx-i2c.c-991-
drivers/media/usb/em28xx/em28xx-i2c.c:992: retval = i2c_add_adapter(&dev->i2c_adap[bus]);
drivers/media/usb/em28xx/em28xx-i2c.c-993- if (retval < 0) {
drivers/media/usb/em28xx/em28xx-i2c.c-994- dev_err(&dev->intf->dev,
drivers/media/usb/em28xx/em28xx-i2c.c:995: "%s: i2c_add_adapter failed! retval [%d]\n",
drivers/media/usb/em28xx/em28xx-i2c.c-996- __func__, retval);
--
drivers/media/usb/go7007/go7007-i2c.c=204=int go7007_i2c_init(struct go7007 *go)
--
drivers/media/usb/go7007/go7007-i2c.c-209- i2c_set_adapdata(&go->i2c_adapter, go);
drivers/media/usb/go7007/go7007-i2c.c:210: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
drivers/media/usb/go7007/go7007-i2c.c-211- dev_err(go->dev,
drivers/media/usb/go7007/go7007-i2c.c:212: "go7007-i2c: error: i2c_add_adapter failed\n");
drivers/media/usb/go7007/go7007-i2c.c-213- return -1;
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1171- i2c_set_adapdata(&go->i2c_adapter, go);
drivers/media/usb/go7007/go7007-usb.c:1172: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
drivers/media/usb/go7007/go7007-usb.c:1173: dev_err(go->dev, "error: i2c_add_adapter failed\n");
drivers/media/usb/go7007/go7007-usb.c-1174- goto allocfail;
--
drivers/media/usb/hdpvr/hdpvr-i2c.c=180=int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
--
drivers/media/usb/hdpvr/hdpvr-i2c.c-188-
drivers/media/usb/hdpvr/hdpvr-i2c.c:189: return i2c_add_adapter(&dev->i2c_adapter);
drivers/media/usb/hdpvr/hdpvr-i2c.c-190-}
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c=591=void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-627- i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c:628: i2c_add_adapter(&hdw->i2c_adap);
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-629- if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
--
drivers/media/usb/stk1160/stk1160-i2c.c=247=int stk1160_i2c_register(struct stk1160 *dev)
--
drivers/media/usb/stk1160/stk1160-i2c.c-257-
drivers/media/usb/stk1160/stk1160-i2c.c:258: rc = i2c_add_adapter(&dev->i2c_adap);
drivers/media/usb/stk1160/stk1160-i2c.c-259- if (rc < 0) {
--
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c=1597=static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
--
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c-1655-
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c:1656: result = i2c_add_adapter(&ttusb->i2c_adap);
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c-1657- if (result)
]
|
| 320/2 |
2026/07/30 13:14 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 148342
output: 50
thoughts: 29
Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience, presented in the first person:
**Initial Assessment: A Familiar Face and a Code Dive**
Ah, *`go7007`*! I recognize that one. Another potential area to explore, always good to keep up with these sorts of things. Let's start with a deep dive into the code. My instinct is telling me to start at `go7007-usb.c` and work from there. Seems like the logical place to begin peeling back the layers.
|
| 321/2 |
2026/07/30 13:14 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1160 LineCount:50]
Results: map[Contents:1160: /* Boot the GO7007 */
1161: if (go7007_boot_encoder(go, go->board_info->flags &
1162: GO7007_BOARD_USE_ONBOARD_I2C) < 0)
1163: goto allocfail;
1164:
1165: /* Register the EZ-USB I2C adapter, if we're using it */
1166: if (board->flags & GO7007_USB_EZUSB_I2C) {
1167: memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
1168: sizeof(go7007_usb_adap_templ));
1169: mutex_init(&usb->i2c_lock);
1170: go->i2c_adapter.dev.parent = go->dev;
1171: i2c_set_adapdata(&go->i2c_adapter, go);
1172: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
1173: dev_err(go->dev, "error: i2c_add_adapter failed\n");
1174: goto allocfail;
1175: }
1176: go->i2c_adapter_online = 1;
1177: }
1178:
1179: /* Pelco and Adlink reused the XMen and XMen-III vendor and product
1180: * IDs for their own incompatible designs. We can detect XMen boards
1181: * by probing the sensor, but there is no way to probe the sensors on
1182: * the Pelco and Adlink designs so we default to the Adlink. If it
1183: * is actually a Pelco, the user must set the assume_endura module
1184: * parameter. */
1185: if ((go->board_id == GO7007_BOARDID_XMEN ||
1186: go->board_id == GO7007_BOARDID_XMEN_III) &&
1187: go->i2c_adapter_online) {
1188: union i2c_smbus_data data;
1189:
1190: /* Check to see if register 0x0A is 0x76 */
1191: i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,
1192: I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);
1193: if (data.byte != 0x76) {
1194: if (assume_endura) {
1195: go->board_id = GO7007_BOARDID_ENDURA;
1196: usb->board = board = &board_endura;
1197: go->board_info = &board->main_info;
1198: strscpy(go->name, "Pelco Endura",
1199: sizeof(go->name));
1200: } else {
1201: u16 channel;
1202:
1203: /* read channel number from GPIO[1:0] */
1204: if (go7007_read_addr(go, 0x3c81, &channel))
1205: goto allocfail;
1206:
1207: channel &= 0x3;
1208: go->board_id = GO7007_BOARDID_ADLINK_MPG24;
1209: usb->board = board = &board_adlink_mpg24;
]
|
| 322/2 |
2026/07/30 13:14 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 149559
output: 50
thoughts: 101
Thoughts: Here's my understanding of the situation, tailored for my expert perspective:
**Debugging the I2C Communication in `go7007`**
Okay, so `go7007` is registering the I2C adapter, which is good. That's the expected initialization step. It's then calling `i2c_smbus_xfer`, which is where the rubber meets the road. This is the function that actually attempts to transfer data over the I2C bus, likely reading a value, given the context.
My immediate concern is what happens if that `i2c_smbus_xfer` call *fails*. Looking at the code, it seems like failure might lead to the `allocfail` label. A failure here is crucial, as any disruption in I2C communication is likely a sign of a larger, systemic problem in the adapter's functionality or the bus itself.
Specifically, I'm watching the read to address `0x3c81`, which, if it fails, jumps to `allocfail`. I need to figure out why this read is failing. Is it an issue with the I2C address, the device itself, the bus arbitration, or a driver bug? My debugging process is going to start right there.
|
| 323/2 |
2026/07/30 13:14 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1210 LineCount:50]
Results: map[Contents:1210: go->board_info = &board->main_info;
1211: go->channel_number = channel;
1212: snprintf(go->name, sizeof(go->name),
1213: "Adlink PCI-MPG24, channel #%d",
1214: channel);
1215: }
1216: go7007_update_board(go);
1217: }
1218: }
1219:
1220: num_i2c_devs = go->board_info->num_i2c_devs;
1221:
1222: /* Probe the tuner model on the TV402U */
1223: if (go->board_id == GO7007_BOARDID_PX_TV402U) {
1224: /* Board strapping indicates tuner model */
1225: if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3,
1226: 1) < 0) {
1227: dev_err(go->dev, "GPIO read failed!\n");
1228: goto allocfail;
1229: }
1230: switch (go->usb_buf[0] >> 6) {
1231: case 1:
1232: go->tuner_type = TUNER_SONY_BTF_PG472Z;
1233: go->std = V4L2_STD_PAL;
1234: strscpy(go->name, "Plextor PX-TV402U-EU",
1235: sizeof(go->name));
1236: break;
1237: case 2:
1238: go->tuner_type = TUNER_SONY_BTF_PK467Z;
1239: go->std = V4L2_STD_NTSC_M_JP;
1240: num_i2c_devs -= 2;
1241: strscpy(go->name, "Plextor PX-TV402U-JP",
1242: sizeof(go->name));
1243: break;
1244: case 3:
1245: go->tuner_type = TUNER_SONY_BTF_PB463Z;
1246: num_i2c_devs -= 2;
1247: strscpy(go->name, "Plextor PX-TV402U-NA",
1248: sizeof(go->name));
1249: break;
1250: default:
1251: pr_debug("unable to detect tuner type!\n");
1252: break;
1253: }
1254: /* Configure tuner mode selection inputs connected
1255: * to the EZ-USB GPIO output pins */
1256: if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
1257: NULL, 0, 0) < 0) {
1258: dev_err(go->dev, "GPIO write failed!\n");
1259: goto allocfail;
]
|
| 324/2 |
2026/07/30 13:14 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 150879
output: 50
thoughts: 10
Thoughts: Okay, here's my summary, framed as my internal thought process:
**Focusing In: The Allocfail Indicator**
Alright, let's get down to brass tacks. I'm hitting a snag somewhere, and I need to pinpoint the root cause. My immediate thought is, I need to see `allocfail`. Everything else is noise right now. `allocfail` is the signal I'm looking for, the indicator that everything is hinging on. Forget the periphery; the critical path hinges on the identification and understanding of that particular fault. Time to put on my Sherlock hat and follow the breadcrumbs. I know what to look for, and I won't be distracted until I find it.
|
| 325/2 |
2026/07/30 13:14 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1260 LineCount:50]
Results: map[Contents:1260: }
1261: }
1262:
1263: /* Print a nasty message if the user attempts to use a USB2.0 device in
1264: * a USB1.1 port. There will be silent corruption of the stream. */
1265: if ((board->flags & GO7007_USB_EZUSB) &&
1266: usbdev->speed != USB_SPEED_HIGH)
1267: dev_err(go->dev, "*** WARNING *** This device must be connected to a USB 2.0 port! Attempting to capture video through a USB 1.1 port will result in stream corruption, even at low bitrates!\n");
1268:
1269: /* Allocate the URBs and buffers for receiving the video stream */
1270: if (board->flags & GO7007_USB_EZUSB) {
1271: if (!usb->usbdev->ep_in[6])
1272: goto allocfail;
1273: v_urb_len = 1024;
1274: video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);
1275: } else {
1276: if (!usb->usbdev->ep_in[1])
1277: goto allocfail;
1278: v_urb_len = 512;
1279: video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
1280: }
1281: for (i = 0; i < 8; ++i) {
1282: usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
1283: if (usb->video_urbs[i] == NULL)
1284: goto allocfail;
1285: usb->video_urbs[i]->transfer_buffer =
1286: kmalloc(v_urb_len, GFP_KERNEL);
1287: if (usb->video_urbs[i]->transfer_buffer == NULL)
1288: goto allocfail;
1289: usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
1290: usb->video_urbs[i]->transfer_buffer, v_urb_len,
1291: go7007_usb_read_video_pipe_complete, go);
1292: }
1293:
1294: /* Allocate the URBs and buffers for receiving the audio stream */
1295: if ((board->flags & GO7007_USB_EZUSB) &&
1296: (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) {
1297: if (!usb->usbdev->ep_in[8])
1298: goto allocfail;
1299: for (i = 0; i < 8; ++i) {
1300: usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
1301: if (usb->audio_urbs[i] == NULL)
1302: goto allocfail;
1303: usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,
1304: GFP_KERNEL);
1305: if (usb->audio_urbs[i]->transfer_buffer == NULL)
1306: goto allocfail;
1307: usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,
1308: usb_rcvbulkpipe(usb->usbdev, 8),
1309: usb->audio_urbs[i]->transfer_buffer, 4096,
]
|
| 326/2 |
2026/07/30 13:14 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 152086
output: 50
thoughts: 10
Thoughts: Okay, here's my summary, framed as my internal thought process:
**Focusing In: The Allocfail Indicator**
Alright, let's get down to brass tacks. I'm hitting a snag somewhere, and I need to pinpoint the root cause. My immediate thought is, I need to see `allocfail`. Everything else is noise right now. `allocfail` is the signal I'm looking for, the indicator that everything is hinging on. Forget the periphery; the critical path hinges on the identification and understanding of that particular fault. Time to put on my Sherlock hat and follow the breadcrumbs. I know what to look for, and I won't be distracted until I find it.
|
| 327/2 |
2026/07/30 13:14 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1310 LineCount:50]
Results: map[Contents:1310: go7007_usb_read_audio_pipe_complete, go);
1311: }
1312: }
1313:
1314: /* Do any final GO7007 initialization, then register the
1315: * V4L2 and ALSA interfaces */
1316: if (go7007_register_encoder(go, num_i2c_devs) < 0)
1317: goto allocfail;
1318:
1319: go->status = STATUS_ONLINE;
1320: return 0;
1321:
1322: allocfail:
1323: go7007_usb_release(go);
1324: kfree(go);
1325: return -ENOMEM;
1326: }
1327:
1328: static void go7007_usb_disconnect(struct usb_interface *intf)
1329: {
1330: struct go7007 *go = to_go7007(usb_get_intfdata(intf));
1331:
1332: mutex_lock(&go->queue_lock);
1333: mutex_lock(&go->serialize_lock);
1334:
1335: if (go->audio_enabled)
1336: go7007_snd_remove(go);
1337:
1338: go->status = STATUS_SHUTDOWN;
1339: v4l2_device_disconnect(&go->v4l2_dev);
1340: video_unregister_device(&go->vdev);
1341: mutex_unlock(&go->serialize_lock);
1342: mutex_unlock(&go->queue_lock);
1343:
1344: v4l2_device_put(&go->v4l2_dev);
1345: }
1346:
1347: static struct usb_driver go7007_usb_driver = {
1348: .name = "go7007",
1349: .probe = go7007_usb_probe,
1350: .disconnect = go7007_usb_disconnect,
1351: .id_table = go7007_usb_id_table,
1352: };
1353:
1354: module_usb_driver(go7007_usb_driver);
1355: MODULE_DESCRIPTION("WIS GO7007 USB support");
1356: MODULE_LICENSE("GPL v2");
]
|
| 328/2 |
2026/07/30 13:14 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 153029
output: 49
thoughts: 37
Thoughts: Here's my thought process, as if I were analyzing this code:
**Analyzing the Allocation Failure and USB Release**
Okay, so I see an `allocfail` call, which is a big red flag β allocation failure is never a good thing. Now, it seems this is tied directly to `go7007_usb_release(go)`. That function is the critical piece here; I need to understand what it's doing. I need to dive into `go7007_usb_release` immediately. Knowing how this release function interacts with the hardware, the resources, and any potential locks is paramount to understanding where the failure occurs. Any unreleased resources may be causing the problem so it's critical to ascertain what `go7007_usb_release` is actually doing. The allocation failure could be symptomatic of an underlying issue, such as memory corruption or resource exhaustion. I need to figure out the chain of events that leads to this `allocfail` and specifically how `go7007_usb_release` fits into that sequence.
|
| 329/2 |
2026/07/30 13:15 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:980 LineCount:50]
Results: map[Contents: 980: } else if (msgs[i].flags & I2C_M_RD) {
981: #ifdef GO7007_I2C_DEBUG
982: pr_debug("i2c read %d bytes on %02x\n",
983: msgs[i].len, msgs[i].addr);
984: #endif
985: buf[0] = 0x01;
986: buf[1] = 1;
987: buf[2] = msgs[i].addr << 1;
988: buf[3] = msgs[i].len;
989: buf_len = 4;
990: } else {
991: #ifdef GO7007_I2C_DEBUG
992: pr_debug("i2c write %d bytes on %02x\n",
993: msgs[i].len, msgs[i].addr);
994: #endif
995: buf[0] = 0x00;
996: buf[1] = msgs[i].len + 1;
997: buf[2] = msgs[i].addr << 1;
998: memcpy(&buf[3], msgs[i].buf, msgs[i].len);
999: buf_len = msgs[i].len + 3;
1000: buf[buf_len++] = 0;
1001: }
1002: if (go7007_usb_vendor_request(go, 0x24, 0, 0,
1003: buf, buf_len, 0) < 0)
1004: goto i2c_done;
1005: if (msgs[i].flags & I2C_M_RD) {
1006: memset(buf, 0, msgs[i].len + 1);
1007: if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf,
1008: msgs[i].len + 1, 1) < 0)
1009: goto i2c_done;
1010: memcpy(msgs[i].buf, buf + 1, msgs[i].len);
1011: }
1012: }
1013: ret = num;
1014:
1015: i2c_done:
1016: mutex_unlock(&usb->i2c_lock);
1017: return ret;
1018: }
1019:
1020: static u32 go7007_usb_functionality(struct i2c_adapter *adapter)
1021: {
1022: /* No errors are reported by the hardware, so we don't bother
1023: * supporting quick writes to avoid confusing probing */
1024: return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK;
1025: }
1026:
1027: static const struct i2c_algorithm go7007_usb_algo = {
1028: .master_xfer = go7007_usb_i2c_master_xfer,
1029: .functionality = go7007_usb_functionality,
]
|
| 330/2 |
2026/07/30 13:15 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 154279
output: 50
thoughts: 22
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience and written in the first person:
**Navigating the USB Release Function**
Okay, so I'm looking at this code and trying to trace the USB release process, and my initial thought is, "Wait a minute, `go7007_usb_release`... that's at line 1030?" I need to verify that location, but its placement raises a flag. It's further down than I expected given my mental model of the module's architecture. It feels like this release function might be buried deeper in the initialization. I'll need to remember this for context when I trace the calls and ensure this is where it is defined.
|
| 331/2 |
2026/07/30 13:15 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1030 LineCount:50]
Results: map[Contents:1030: };
1031:
1032: static struct i2c_adapter go7007_usb_adap_templ = {
1033: .owner = THIS_MODULE,
1034: .name = "WIS GO7007SB EZ-USB",
1035: .algo = &go7007_usb_algo,
1036: };
1037:
1038: /********************* USB add/remove functions *********************/
1039:
1040: static int go7007_usb_probe(struct usb_interface *intf,
1041: const struct usb_device_id *id)
1042: {
1043: struct go7007 *go;
1044: struct go7007_usb *usb;
1045: const struct go7007_usb_board *board;
1046: struct usb_device *usbdev = interface_to_usbdev(intf);
1047: struct usb_host_endpoint *ep;
1048: unsigned num_i2c_devs;
1049: char *name;
1050: int video_pipe, i, v_urb_len;
1051:
1052: pr_debug("probing new GO7007 USB board\n");
1053:
1054: switch (id->driver_info) {
1055: case GO7007_BOARDID_MATRIX_II:
1056: name = "WIS Matrix II or compatible";
1057: board = &board_matrix_ii;
1058: break;
1059: case GO7007_BOARDID_MATRIX_RELOAD:
1060: name = "WIS Matrix Reloaded or compatible";
1061: board = &board_matrix_reload;
1062: break;
1063: case GO7007_BOARDID_MATRIX_REV:
1064: name = "WIS Matrix Revolution or compatible";
1065: board = &board_matrix_revolution;
1066: break;
1067: case GO7007_BOARDID_STAR_TREK:
1068: name = "WIS Star Trek or compatible";
1069: board = &board_star_trek;
1070: break;
1071: case GO7007_BOARDID_XMEN:
1072: name = "WIS XMen or compatible";
1073: board = &board_xmen;
1074: break;
1075: case GO7007_BOARDID_XMEN_II:
1076: name = "WIS XMen II or compatible";
1077: board = &board_xmen;
1078: break;
1079: case GO7007_BOARDID_XMEN_III:
]
|
| 332/2 |
2026/07/30 13:15 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 155309
output: 23
thoughts: 51
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Debugging a Missing Symbol**
Hmm, hold on a second. I was *certain* that `go7007_usb_release` was defined within the `go7007-usb.c` file. I was referencing that file in my previous analysis, and assumed that this must be the case. But, after a quick check, I realize I was mistaken. That function's definition isn't there! This means I've made a faulty assumption, and wasted time chasing a wrong lead. I need to recalibrate. My initial instinct was off. It's almost definitely declared, likely defined, and definitely implemented, somewhere else in the codebase. Given the typical structure of these drivers, the release function probably falls into the v4l2 handling, or at least the v4l2 context, so I should be looking in `go7007-v4l2.c`, or a similar v4l2-specific file, or something along those lines. Time to adjust my search parameters. Let's see what turns up in the v4l2 implementation.
|
| 333/2 |
2026/07/30 13:15 |
tool |
grepper |
0m
Args: map[Expression:go7007_usb_release]
Results: map[Output:drivers/media/usb/go7007/go7007-usb.c=879=static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len)
--
drivers/media/usb/go7007/go7007-usb.c-895-
drivers/media/usb/go7007/go7007-usb.c:896:static void go7007_usb_release(struct go7007 *go)
drivers/media/usb/go7007/go7007-usb.c-897-{
--
drivers/media/usb/go7007/go7007-usb.c=927=static const struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
--
drivers/media/usb/go7007/go7007-usb.c-933- .send_firmware = go7007_usb_send_firmware,
drivers/media/usb/go7007/go7007-usb.c:934: .release = go7007_usb_release,
drivers/media/usb/go7007/go7007-usb.c-935-};
--
drivers/media/usb/go7007/go7007-usb.c=937=static const struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
--
drivers/media/usb/go7007/go7007-usb.c-943- .send_firmware = go7007_usb_send_firmware,
drivers/media/usb/go7007/go7007-usb.c:944: .release = go7007_usb_release,
drivers/media/usb/go7007/go7007-usb.c-945-};
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1322-allocfail:
drivers/media/usb/go7007/go7007-usb.c:1323: go7007_usb_release(go);
drivers/media/usb/go7007/go7007-usb.c-1324- kfree(go);
]
|
| 334/2 |
2026/07/30 13:15 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 156323
output: 49
thoughts: 15
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm well-versed in embedded systems and device drivers:
**Analyzing the USB Release Code: `go7007_usb_release`**
Alright, let's dive into this `go7007_usb_release` function. My initial thought is to figure out what device this is associated with, obviously some USB device. Based on the name it seems to be related to the go7007 codec or some derivative, so likely something handling video or audio input/output. The "release" part instantly suggests this is a critical section for cleaning up resources when the device is no longer in use, disconnected, or the driver is being unloaded. I'll need to scrutinize what it's *actually* releasing.
I'm expecting to see calls to `usb_free_urb()` and `usb_put_intf()` at a minimum. Probably also calls to `kfree()`ing any dynamically allocated memory associated with the device's private data, buffer, or descriptors. It's likely handling things like canceling any pending URBs (USB Request Blocks) to prevent data corruption or hangs, and releasing any claimed USB interfaces. It's crucial this code is robust, otherwise, we'll see memory leaks, resource contention, or even system crashes. I'll be looking carefully at the locking mechanisms used (mutexes, spinlocks) to ensure thread safety during the release process, especially if the device can be disconnected while actively being used. I'll also check if there's any error handling, such as error codes or logging, to help diagnose potential issues if the release fails for some reason. The goal here is to ensure a clean exit, preventing any dangling resources or causing side effects for other devices or applications.
|
| 335/2 |
2026/07/30 13:15 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:890 LineCount:50]
Results: map[Contents: 890: pipe = usb_sndbulkpipe(usb->usbdev, 3);
891:
892: return usb_bulk_msg(usb->usbdev, pipe, data, len,
893: &transferred, timeout);
894: }
895:
896: static void go7007_usb_release(struct go7007 *go)
897: {
898: struct go7007_usb *usb = go->hpi_context;
899: struct urb *vurb, *aurb;
900: int i;
901:
902: if (usb->intr_urb) {
903: usb_kill_urb(usb->intr_urb);
904: kfree(usb->intr_urb->transfer_buffer);
905: usb_free_urb(usb->intr_urb);
906: }
907:
908: /* Free USB-related structs */
909: for (i = 0; i < 8; ++i) {
910: vurb = usb->video_urbs[i];
911: if (vurb) {
912: usb_kill_urb(vurb);
913: kfree(vurb->transfer_buffer);
914: usb_free_urb(vurb);
915: }
916: aurb = usb->audio_urbs[i];
917: if (aurb) {
918: usb_kill_urb(aurb);
919: kfree(aurb->transfer_buffer);
920: usb_free_urb(aurb);
921: }
922: }
923:
924: kfree(go->hpi_context);
925: }
926:
927: static const struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
928: .interface_reset = go7007_usb_interface_reset,
929: .write_interrupt = go7007_usb_ezusb_write_interrupt,
930: .read_interrupt = go7007_usb_read_interrupt,
931: .stream_start = go7007_usb_stream_start,
932: .stream_stop = go7007_usb_stream_stop,
933: .send_firmware = go7007_usb_send_firmware,
934: .release = go7007_usb_release,
935: };
936:
937: static const struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
938: .interface_reset = go7007_usb_interface_reset,
939: .write_interrupt = go7007_usb_onboard_write_interrupt,
]
|
| 336/2 |
2026/07/30 13:15 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 157624
output: 50
thoughts: 654
Thoughts: **Analyzing a Potential Use-After-Free Vulnerability in the go7007 USB Driver**
Okay, hold on a second. I need to think this through. The `go7007_usb_release` function *doesn't* call `i2c_del_adapter`? That's the first red flag. Now, if the `go7007_usb_probe` function encounters an `allocfail`, it does call `go7007_usb_release(go)` and then `kfree(go)`. The problem is, `i2c_add_adapter` was called *before* the potential `allocfail`!
Looking at the code again... if we reach `allocfail` *after* `i2c_add_adapter` is successful, it frees the `go` structure without deleting the associated I2C adapter. That looks like a massive use-after-free vulnerability right there. But wait a moment... the `go->i2c_adapter` struct is actually embedded directly within the `struct go7007` structure, isn't it? So, freeing `go` *should* free the I2C adapter as well. However, it's still registered within the I2C core, which means any subsequent attempt to access the I2C adapter will actually result in a use-after-free on `go`.
Okay, the bug report... the KASAN output confirms this: "slab-use-after-free in i2c_adapter_lock_bus". It's pointing to a read of size 8 at a specific memory address, and crucially, it says the buggy address belongs to an object in the `kmalloc-4k` cache.
Now, if `kzalloc` is used to allocate `struct go7007`, does the size of `struct go7007` approximate 4096 bytes? I need to check the definition of that structure... this all depends on the sizes of its members and whether it's aligned for a 4k allocation. This could be a significant issue if the struct size is close enough to 4k.
|
| 337/2 |
2026/07/30 13:16 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-priv.h FirstLine:140 LineCount:100]
Results: map[Contents: 140:
141: enum go7007_parser_state {
142: STATE_DATA,
143: STATE_00,
144: STATE_00_00,
145: STATE_00_00_01,
146: STATE_FF,
147: STATE_VBI_LEN_A,
148: STATE_VBI_LEN_B,
149: STATE_MODET_MAP,
150: STATE_UNPARSED,
151: };
152:
153: struct go7007 {
154: struct device *dev;
155: u8 bus_info[32];
156: const struct go7007_board_info *board_info;
157: unsigned int board_id;
158: int tuner_type;
159: int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */
160: char name[64];
161: struct video_device vdev;
162: void *boot_fw;
163: unsigned boot_fw_len;
164: struct v4l2_device v4l2_dev;
165: struct v4l2_ctrl_handler hdl;
166: struct v4l2_ctrl *mpeg_video_encoding;
167: struct v4l2_ctrl *mpeg_video_gop_size;
168: struct v4l2_ctrl *mpeg_video_gop_closure;
169: struct v4l2_ctrl *mpeg_video_bitrate;
170: struct v4l2_ctrl *mpeg_video_aspect_ratio;
171: struct v4l2_ctrl *mpeg_video_b_frames;
172: struct v4l2_ctrl *mpeg_video_rep_seqheader;
173: struct v4l2_ctrl *modet_mode;
174: enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status;
175: spinlock_t spinlock;
176: struct mutex hw_lock;
177: struct mutex serialize_lock;
178: int audio_enabled;
179: struct v4l2_subdev *sd_video;
180: struct v4l2_subdev *sd_audio;
181: u8 usb_buf[16];
182:
183: /* Video input */
184: int input;
185: int aud_input;
186: enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard;
187: v4l2_std_id std;
188: int sensor_framerate;
189: int width;
190: int height;
191: int encoder_h_offset;
192: int encoder_v_offset;
193: unsigned int encoder_h_halve:1;
194: unsigned int encoder_v_halve:1;
195: unsigned int encoder_subsample:1;
196:
197: /* Encoder config */
198: u32 format;
199: int bitrate;
200: int fps_scale;
201: int pali;
202: int aspect_ratio;
203: int gop_size;
204: unsigned int ipb:1;
205: unsigned int closed_gop:1;
206: unsigned int repeat_seqhead:1;
207: unsigned int seq_header_enable:1;
208: unsigned int gop_header_enable:1;
209: unsigned int dvd_mode:1;
210: unsigned int interlace_coding:1;
211:
212: /* Motion detection */
213: unsigned int modet_enable:1;
214: struct {
215: unsigned int enable:1;
216: int pixel_threshold;
217: int motion_threshold;
218: int mb_threshold;
219: } modet[4];
220: unsigned char modet_map[1624];
221: unsigned char active_map[216];
222: u32 modet_event_status;
223:
224: /* Video streaming */
225: struct mutex queue_lock;
226: struct vb2_queue vidq;
227: enum go7007_parser_state state;
228: int parse_length;
229: u16 modet_word;
230: int seen_frame;
231: u32 next_seq;
232: struct list_head vidq_active;
233: wait_queue_head_t frame_waitq;
234: struct go7007_buffer *active_buf;
235:
236: /* Audio streaming */
237: void (*audio_deliver)(struct go7007 *go, u8 *buf, int length);
238: void *snd_context;
239:
]
|
| 338/2 |
2026/07/30 13:16 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 160306
output: 50
thoughts: 522
Thoughts: **Analyzing a Potential I2C Adapter Leak in the go7007 Driver**
Okay, let's break this down. First, I'm looking at `struct go7007` and immediately see that it's substantial β it contains a sizable `struct video_device vdev`, alongside `struct v4l2_device v4l2_dev`, `unsigned char modet_map[1624]`, and `struct vb2_queue vidq`. Based on those members, it's very probable that the `struct go7007` instance is around 4KB in size.
The crux of the issue is what I suspected: `i2c_add_adapter` gets called, but if `go7007_usb_probe` subsequently fails, the `go` structure is freed *without* the corresponding `i2c_del_adapter` call. That's a classic resource leak, a textbook I2C adapter leak.
Now, I need to pinpoint where exactly `go7007_usb_probe` can fail *after* the `i2c_add_adapter` call to confirm this. I see the code checks for specific board IDs (`GO7007_BOARDID_XMEN` or `GO7007_BOARDID_XMEN_III`) and if the I2C adapter is online. Crucially, a specific I2C SMBus read is performed to verify register `0x0A`'s value. If that value is incorrect, it proceeds to read a channel number using `go7007_read_addr`. If *that* call fails, the function jumps to `allocfail`.
Aha! `go7007_read_addr` is the likely culprit. It's making a vendor-specific control message. If the device, or, as it seems is the case here, syzkaller, doesn't reply to that message, the call fails. This provides a very easy path to trigger the leak. The key is that `go->board_id` must be either `GO7007_BOARDID_XMEN` or `GO7007_BOARDID_XMEN_III`, so I'll check `go7007_usb_id_table` to confirm that the `XMEN` board ID is indeed associated with any USB device.
|
| 339/2 |
2026/07/30 13:16 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1350 LineCount:50]
Results: map[Contents:1350: .disconnect = go7007_usb_disconnect,
1351: .id_table = go7007_usb_id_table,
1352: };
1353:
1354: module_usb_driver(go7007_usb_driver);
1355: MODULE_DESCRIPTION("WIS GO7007 USB support");
1356: MODULE_LICENSE("GPL v2");
]
|
| 340/2 |
2026/07/30 13:16 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 161528
output: 25
thoughts: 19
Thoughts: Here's my summary, as the expert:
**Investigating the USB ID Table**
Okay, hold on a second. I'm going through this code, and I just saw a reference to `go7007_usb_id_table`. Hmm, let me think... didn't I see that definition earlier? I'm almost certain it's defined upstream in the initialization or device enumeration section. I need to go back and double-check where that table is actually created or populated. It's crucial because that table is the cornerstone for how the USB driver identifies and interacts with the specific go7007 devices. Understanding *when* and *how* that table gets populated is going to be central to debugging anything that comes next. I can't proceed further until I have a clear picture of that.
|
| 341/2 |
2026/07/30 13:16 |
tool |
grepper |
0m
Args: map[Expression:go7007_usb_id_table]
Results: map[Output:drivers/media/usb/go7007/go7007-usb.c=469=static const struct go7007_usb_board board_ads_usbav_709 = {
--
drivers/media/usb/go7007/go7007-usb.c-505-
drivers/media/usb/go7007/go7007-usb.c:506:static const struct usb_device_id go7007_usb_id_table[] = {
drivers/media/usb/go7007/go7007-usb.c-507- {
--
drivers/media/usb/go7007/go7007-usb.c-617-
drivers/media/usb/go7007/go7007-usb.c:618:MODULE_DEVICE_TABLE(usb, go7007_usb_id_table);
drivers/media/usb/go7007/go7007-usb.c-619-
--
drivers/media/usb/go7007/go7007-usb.c=1347=static struct usb_driver go7007_usb_driver = {
--
drivers/media/usb/go7007/go7007-usb.c-1350- .disconnect = go7007_usb_disconnect,
drivers/media/usb/go7007/go7007-usb.c:1351: .id_table = go7007_usb_id_table,
drivers/media/usb/go7007/go7007-usb.c-1352-};
]
|
| 342/2 |
2026/07/30 13:16 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 162186
output: 50
thoughts: 17
Thoughts: Okay, here's my attempt at summarizing the thought process, as requested, aimed at an expert user:
**Diving into the USB ID Table**
Right, let's get into this. I see `go7007_usb_id_table` β so that immediately tells me we're looking at device identification related to the GO7007 USB interface. I'm already anticipating a table filled with vendor IDs, product IDs, and potentially interface class codes, subclass codes, and protocol codes β the usual suspects. Iβm guessing this file is crucial for the USB driver to recognize and correctly initialize devices based on the GO7007 chipset.
I'll be looking for any nuances, potential overrides, or perhaps even blacklists within this table. Given my experience, I'll be particularly interested in any vendor or product IDs I'm familiar with, or conversely, any I've never encountered before. New IDs often signal new hardware revisions or manufacturers, so I'll need to assess if this aligns with anything I've seen in recent hardware releases. Iβm thinking in particular about any edge cases or unusual combinations that may have been reported as bugs in the past.
I also want to pay close attention to the granularity of the entries. Are there specific entries for different firmware revisions or hardware variants of the GO7007 devices? That level of detail could be critical for avoiding conflicts and ensuring compatibility. Any vendor or product IDs that seem generic will immediately catch my attention. They might indicate a driver that's attempting to be overly broad in its device matching, which could lead to instability or incorrect functionality.
Essentially, I need to get a clear picture of how this ID table fits within the broader picture of the GO7007 USB driver and how it handles device identification and initial setup. I'm going to scan the data, cross-reference it with any relevant documentation or known issues, and immediately flag anything that appears unusual or potentially problematic.
|
| 343/2 |
2026/07/30 13:16 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:500 LineCount:100]
Results: map[Contents: 500: .name = "S-Video",
501: },
502: },
503: },
504: };
505:
506: static const struct usb_device_id go7007_usb_id_table[] = {
507: {
508: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
509: USB_DEVICE_ID_MATCH_INT_INFO,
510: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
511: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
512: .bcdDevice_lo = 0x200, /* Revision number of XMen */
513: .bcdDevice_hi = 0x200,
514: .bInterfaceClass = 255,
515: .bInterfaceSubClass = 0,
516: .bInterfaceProtocol = 255,
517: .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN,
518: },
519: {
520: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
521: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
522: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
523: .bcdDevice_lo = 0x202, /* Revision number of Matrix II */
524: .bcdDevice_hi = 0x202,
525: .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II,
526: },
527: {
528: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
529: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
530: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
531: .bcdDevice_lo = 0x204, /* Revision number of Matrix */
532: .bcdDevice_hi = 0x204, /* Reloaded */
533: .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD,
534: },
535: {
536: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
537: USB_DEVICE_ID_MATCH_INT_INFO,
538: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
539: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
540: .bcdDevice_lo = 0x205, /* Revision number of XMen-II */
541: .bcdDevice_hi = 0x205,
542: .bInterfaceClass = 255,
543: .bInterfaceSubClass = 0,
544: .bInterfaceProtocol = 255,
545: .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_II,
546: },
547: {
548: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
549: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
550: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
551: .bcdDevice_lo = 0x208, /* Revision number of Star Trek */
552: .bcdDevice_hi = 0x208,
553: .driver_info = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK,
554: },
555: {
556: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
557: USB_DEVICE_ID_MATCH_INT_INFO,
558: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
559: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
560: .bcdDevice_lo = 0x209, /* Revision number of XMen-III */
561: .bcdDevice_hi = 0x209,
562: .bInterfaceClass = 255,
563: .bInterfaceSubClass = 0,
564: .bInterfaceProtocol = 255,
565: .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_III,
566: },
567: {
568: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
569: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
570: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
571: .bcdDevice_lo = 0x210, /* Revision number of Matrix */
572: .bcdDevice_hi = 0x210, /* Revolution */
573: .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV,
574: },
575: {
576: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
577: .idVendor = 0x093b, /* Vendor ID of Plextor */
578: .idProduct = 0xa102, /* Product ID of M402U */
579: .bcdDevice_lo = 0x1, /* revision number of Blueberry */
580: .bcdDevice_hi = 0x1,
581: .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_M402U,
582: },
583: {
584: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
585: .idVendor = 0x093b, /* Vendor ID of Plextor */
586: .idProduct = 0xa104, /* Product ID of TV402U */
587: .bcdDevice_lo = 0x1,
588: .bcdDevice_hi = 0x1,
589: .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U,
590: },
591: {
592: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
593: .idVendor = 0x10fd, /* Vendor ID of Anubis Electronics */
594: .idProduct = 0xde00, /* Product ID of Lifeview LR192 */
595: .bcdDevice_lo = 0x1,
596: .bcdDevice_hi = 0x1,
597: .driver_info = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192,
598: },
599: {
]
|
| 344/2 |
2026/07/30 13:16 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 164847
output: 49
thoughts: 536
Thoughts: **Analyzing the XMEN Device**
Okay, so I've identified a device β `0x0eb1:0x7007` β as the `XMEN`. Let's see... its `bcdDevice` is `0x200`. And the interface details? `bInterfaceClass = 255`, `bInterfaceSubClass = 0`, and `bInterfaceProtocol = 255`. Now, let's build the `ANY` blob for `go7007`.
First, the Device Descriptor (18 bytes): `12 01 00 02 00 00 00 40 b1 0e 07 70 00 02 00 00 00 01`. I'm just double-checking... right, `bcdDevice` being `0x200` means `00 02` in little-endian. Seems correct.
Next, the Configuration Descriptor (9 bytes): `09 02 22 00 01 01 00 80 00`. And the Interface Descriptor (9 bytes): `09 04 00 00 01 ff 00 ff 00`.
Finally, the Endpoint Descriptor (7 bytes): `07 05 81 02 40 00 00`. It's `0x81` for `bEndpointAddress` (IN), `2` for `bmAttributes` (Bulk), `64` for `wMaxPacketSize`, and `0` for `bInterval`. Good.
Right, so for `go7007` itself, it needs either `ep_in[6]` or `ep_in[1]`. According to the code, it depends on the `GO7007_USB_EZUSB` flag. If that flag is set, then use `ep_in[6]`. If not, then use `ep_in[1]`. Makes sense.
Now, does this `XMEN` have the `GO7007_USB_EZUSB` flag set? Need to check the `board_xmen` definition to be sure. That's the next step.
|
| 345/2 |
2026/07/30 13:16 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:200 LineCount:50]
Results: map[Contents: 200: GO7007_AUDIO_WORD_16,
201: .audio_bclk_div = 8,
202: .audio_main_div = 2,
203: .hpi_buffer_cap = 7,
204: .num_i2c_devs = 5,
205: .i2c_devs = {
206: {
207: .type = "saa7115",
208: .addr = 0x20,
209: .is_video = 1,
210: },
211: {
212: .type = "uda1342",
213: .addr = 0x1a,
214: .is_audio = 1,
215: },
216: {
217: .type = "tuner",
218: .addr = 0x60,
219: },
220: {
221: .type = "tuner",
222: .addr = 0x43,
223: },
224: {
225: .type = "sony-btf-mpx",
226: .addr = 0x44,
227: },
228: },
229: .num_inputs = 3,
230: .inputs = {
231: {
232: .video_input = 3,
233: .audio_index = 0,
234: .name = "Tuner",
235: },
236: {
237: .video_input = 1,
238: .audio_index = 1,
239: .name = "Composite",
240: },
241: {
242: .video_input = 8,
243: .audio_index = 1,
244: .name = "S-Video",
245: },
246: },
247: .video_config = SAA7115_IDQ_IS_DEFAULT,
248: .num_aud_inputs = 2,
249: .aud_inputs = {
]
|
| 346/2 |
2026/07/30 13:16 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 166637
output: 18
thoughts: 14
Thoughts: Here's my thought process, summarized as if I were considering the situation:
**Need to Review `board_xmen` Flags**
Okay, first things first, I need to make sure I'm on the right track. My immediate thought is to check for the `board_xmen` flags. I can't proceed effectively until I have a clear understanding of what those flags represent and how they are currently set. This is the foundation upon which I can evaluate the current state and determine next steps. I need to understand the context of those flags before digging deeper into the data. Let me go back and review the documentation on those flags...
|
| 347/2 |
2026/07/30 13:17 |
tool |
grepper |
0m
Args: map[Expression:board_xmen]
Results: map[Output:drivers/media/usb/go7007/go7007-usb.c=188=static const struct go7007_usb_board board_px_tv402u = {
--
drivers/media/usb/go7007/go7007-usb.c-261-
drivers/media/usb/go7007/go7007-usb.c:262:static const struct go7007_usb_board board_xmen = {
drivers/media/usb/go7007/go7007-usb.c-263- .flags = 0,
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1072- name = "WIS XMen or compatible";
drivers/media/usb/go7007/go7007-usb.c:1073: board = &board_xmen;
drivers/media/usb/go7007/go7007-usb.c-1074- break;
--
drivers/media/usb/go7007/go7007-usb.c-1076- name = "WIS XMen II or compatible";
drivers/media/usb/go7007/go7007-usb.c:1077: board = &board_xmen;
drivers/media/usb/go7007/go7007-usb.c-1078- break;
--
drivers/media/usb/go7007/go7007-usb.c-1080- name = "WIS XMen III or compatible";
drivers/media/usb/go7007/go7007-usb.c:1081: board = &board_xmen;
drivers/media/usb/go7007/go7007-usb.c-1082- break;
]
|
| 348/2 |
2026/07/30 13:17 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 167351
output: 49
thoughts: 171
Thoughts: **Analyzing the USB Endpoint Configuration**
Okay, so I'm looking at this `board_xmen` structure and its flags. The code's using those flags to determine how to configure the USB endpoints. Right now, it looks like `board_xmen` has `.flags = 0`. This means that the check `board->flags & GO7007_USB_EZUSB` is evaluating to FALSE. If that's the case, then the code *expects* `ep_in[1]` to be available.
That makes sense, right? Because then there's this block of code:
```
} else {
if (!usb->usbdev->ep_in[1])
goto allocfail;
v_urb_len = 512;
video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
}
```
If the EZUSB flag isn't set, it jumps into that `else` block and uses `ep_in[1]` for video. Then, it's suggesting that `ep_in[8]` is expected for audio.
Hmm, this is where I need to double-check. Does `board_xmen` have `GO7007_BOARD_HAS_AUDIO` defined? I need to go back and look at the `board_xmen` definition to be absolutely certain what the configuration should be. Gotta verify the audio endpoint setup based on the board definition.
|
| 349/2 |
2026/07/30 13:17 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:260 LineCount:50]
Results: map[Contents: 260: };
261:
262: static const struct go7007_usb_board board_xmen = {
263: .flags = 0,
264: .main_info = {
265: .flags = GO7007_BOARD_USE_ONBOARD_I2C,
266: .hpi_buffer_cap = 0,
267: .sensor_flags = GO7007_SENSOR_VREF_POLAR,
268: .sensor_width = 320,
269: .sensor_height = 240,
270: .sensor_framerate = 30030,
271: .audio_flags = GO7007_AUDIO_ONE_CHANNEL |
272: GO7007_AUDIO_I2S_MODE_3 |
273: GO7007_AUDIO_WORD_14 |
274: GO7007_AUDIO_I2S_MASTER |
275: GO7007_AUDIO_BCLK_POLAR |
276: GO7007_AUDIO_OKI_MODE,
277: .audio_rate = 8000,
278: .audio_bclk_div = 48,
279: .audio_main_div = 1,
280: .num_i2c_devs = 1,
281: .i2c_devs = {
282: {
283: .type = "ov7640",
284: .addr = 0x21,
285: },
286: },
287: .num_inputs = 1,
288: .inputs = {
289: {
290: .name = "Camera",
291: },
292: },
293: },
294: };
295:
296: static const struct go7007_usb_board board_matrix_revolution = {
297: .flags = GO7007_USB_EZUSB,
298: .main_info = {
299: .flags = GO7007_BOARD_HAS_AUDIO |
300: GO7007_BOARD_USE_ONBOARD_I2C,
301: .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
302: GO7007_AUDIO_I2S_MASTER |
303: GO7007_AUDIO_WORD_16,
304: .audio_rate = 48000,
305: .audio_bclk_div = 8,
306: .audio_main_div = 2,
307: .hpi_buffer_cap = 7,
308: .sensor_flags = GO7007_SENSOR_656 |
309: GO7007_SENSOR_TV |
]
|
| 350/2 |
2026/07/30 13:17 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 168786
output: 50
thoughts: 605
Thoughts: **I2C Adapter Registration on the XMEN Board**
Okay, let's break this down. `board_xmen` is defined to use `GO7007_BOARD_USE_ONBOARD_I2C`, which means we're dealing with the on-board I2C. The code snippet shows a check for `GO7007_USB_EZUSB_I2C`, but it's clear that *this* specific branch *doesn't* register the I2C adapter if that flag isn't set. That makes sense. But if not here, *where* does it get registered?
Ah, got it! The `go7007_register_encoder` function does the heavy lifting, as it calls `go7007_i2c_init`! That function does call `i2c_add_adapter`, so *that's* where the XMEN's I2C adapter is getting registered, even though the first block of code isn't involved. Good.
The tricky part is that `go7007_register_encoder` is called at the very end of `go7007_usb_probe`, after everything else is supposed to be set up. So, if `go7007_register_encoder` fails, specifically *after* calling `go7007_i2c_init`, the function returns an error and jumps to `allocfail`.
*Here* is the problem: the `allocfail` path cleans up and frees the `go` structure *without* explicitly unregistering the I2C adapter. If `go7007_i2c_init` succeeds, but there's a problem later in the `go7007_register_encoder` function that causes it to fail, we've leaked an I2C adapter! We have to check `go7007_register_encoder` to see what could fail after the I2C init.
|
| 351/2 |
2026/07/30 13:17 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-driver.c FirstLine:600 LineCount:100]
Results: map[Contents: 600: if (vb && go->seen_frame)
601: vb->frame_offset =
602: vb->vb.vb2_buf.planes[0].bytesused;
603: }
604: /* Handle any special chunk types, or just write the
605: * start code to the (potentially new) buffer */
606: switch (buf[i]) {
607: case 0xF5: /* timestamp */
608: go->parse_length = 12;
609: go->state = STATE_UNPARSED;
610: break;
611: case 0xF6: /* vbi */
612: go->state = STATE_VBI_LEN_A;
613: break;
614: case 0xF8: /* MD map */
615: go->parse_length = 0;
616: memset(go->active_map, 0,
617: sizeof(go->active_map));
618: go->state = STATE_MODET_MAP;
619: break;
620: case 0xFF: /* Potential JPEG start code */
621: store_byte(vb, 0x00);
622: store_byte(vb, 0x00);
623: store_byte(vb, 0x01);
624: go->state = STATE_FF;
625: break;
626: default:
627: store_byte(vb, 0x00);
628: store_byte(vb, 0x00);
629: store_byte(vb, 0x01);
630: store_byte(vb, buf[i]);
631: go->state = STATE_DATA;
632: break;
633: }
634: break;
635: case STATE_FF:
636: switch (buf[i]) {
637: case 0x00:
638: store_byte(vb, 0xFF);
639: go->state = STATE_00;
640: break;
641: case 0xFF:
642: store_byte(vb, 0xFF);
643: /* go->state remains STATE_FF */
644: break;
645: case 0xD8:
646: if (go->format == V4L2_PIX_FMT_MJPEG)
647: vb = frame_boundary(go, vb);
648: fallthrough;
649: default:
650: store_byte(vb, 0xFF);
651: store_byte(vb, buf[i]);
652: go->state = STATE_DATA;
653: break;
654: }
655: break;
656: case STATE_VBI_LEN_A:
657: go->parse_length = buf[i] << 8;
658: go->state = STATE_VBI_LEN_B;
659: break;
660: case STATE_VBI_LEN_B:
661: go->parse_length |= buf[i];
662: if (go->parse_length > 0)
663: go->state = STATE_UNPARSED;
664: else
665: go->state = STATE_DATA;
666: break;
667: case STATE_MODET_MAP:
668: if (go->parse_length < 204) {
669: if (go->parse_length & 1) {
670: go->modet_word |= buf[i];
671: write_bitmap_word(go);
672: } else
673: go->modet_word = buf[i] << 8;
674: } else if (go->parse_length == 207 && vb) {
675: vb->modet_active = buf[i];
676: }
677: if (++go->parse_length == 208)
678: go->state = STATE_DATA;
679: break;
680: case STATE_UNPARSED:
681: if (--go->parse_length == 0)
682: go->state = STATE_DATA;
683: break;
684: }
685: }
686: }
687: EXPORT_SYMBOL(go7007_parse_video_stream);
688:
689: /*
690: * Allocate a new go7007 struct. Used by the hardware-specific probe.
691: */
692: struct go7007 *go7007_alloc(const struct go7007_board_info *board,
693: struct device *dev)
694: {
695: struct go7007 *go;
696:
697: go = kzalloc_obj(struct go7007);
698: if (go == NULL)
699: return NULL;
]
|
| 352/2 |
2026/07/30 13:17 |
llm |
crash-repro-finder-compressor |
0m
Model:
Reply: ### 1. Approaches Tried and Results
* **Direct Device Opening**:
* Attempted to open `/dev/video0` and `/dev/i2c-0` directly using `syz_open_dev$video` and `syz_open_dev$I2C` with explicit paths.
* *Result*: Failed with syntax errors because syzkaller requires the exact template string `"/dev/video#\x00"` or `"/dev/i2c-#\x00"`.
* **Generic HID Emulation**:
* Used `syz_usb_connect$hid` to connect a generic HID device.
* *Result*: No crash. Target drivers (`si4713`, `au0828`, `go7007`) were not bound because syzkaller patches vendor/product IDs to match generic HID drivers.
* **Custom USB Descriptor Construction via Structs**:
* Attempted to construct a custom `usb_device_descriptor` for `syz_usb_connect` to emulate `si4713` (Vendor `0x10c4`, Product `0x8244`, Class `USB_CLASS_HID`).
* *Dead-ends & Syntax Errors*:
* `AUTO` cannot be used for `FlagsType` or `ArrayType` fields.
* `void` fields (like `extra` in `usb_config_descriptor_verbose_t`) must be represented as `""` (empty string) in the struct literal.
* `len` fields must be explicitly provided as `AUTO` in the struct literal.
* `usb_interface_descriptor` is a struct with a single field `inner`, requiring nested braces `{{{...}}}` for its array elements.
* `bInterfaceClass` in `usb_interface_descriptor` is hardcoded to `0` in syzkaller's generic definitions, preventing the emulation of `USB_CLASS_HID` (3) using standard structs.
* **USB Emulation via Raw `ANY` Blobs**:
* Attempted to pass a raw byte array for the device descriptor using `&AUTO=ANY=[@ANYBLOB="..."]`.
* *Result*: If the blob is only 18 bytes (device descriptor), the `configs` array is empty, resulting in no configurations and no driver probe.
* *Correction*: Constructed a full 52-byte concatenated USB descriptor blob containing Device, Config, Interface, HID, and Endpoint descriptors:
`"1201000200000040c410448200000000000109022200010100800009040000010300000009211101000122220007058103400001"`
* **Target Driver Investigation**:
* **`si4713`**: Requires complex control message handshakes during `si4713_send_startup_command`. If the handshake fails, the probe fails before `si4713_register_i2c_adapter` is called, meaning the I2C adapter is never registered. This is a dead-end for triggering the UAF.
* **`au0828`**: Requires `USB_SPEED_HIGH` (speed 3) and `bInterfaceNumber = 0`. If `au0828_analog_register` fails (e.g., due to missing alternate setting 5), `au0828_usb_probe` calls `au0828_usb_disconnect` and returns an error. In `au0828_usb_disconnect`, `au0828_analog_unregister` returns 1, causing the disconnect function to return early and skip `au0828_usb_release(dev)`. This leaks `dev` and leaves the I2C adapter registered with a dangling parent pointer to the freed `usb_device`.
### 2. Current Hypotheses & Active Lines of Investigation
* **`au0828` Deferred Cleanup Leak**:
* Emulate an `au0828` USB device (Vendor `0x2040`, Product `0x7200`) with high speed and interface 0.
* Intentionally omit alternate setting 5 to force `au0828_analog_register` to fail during probe.
* The probe failure triggers the early-return bug in `au0828_usb_disconnect`, leaking the registered I2C adapter.
* Disconnect the USB device to free the `usb_device` structure.
* Perform an I2C transaction (e.g., `ioctl$I2C_SMBUS`) on the leaked I2C adapter to trigger the UAF in `i2c_adapter_depth` when it dereferences `adapter->dev.parent->type`.
* **`go7007` Driver Analysis**:
* Investigating if `go7007` (Vendor `0x0eb1`, Product `0x7007`) has a similar I2C adapter registration leak on probe failure or disconnect.
### 3. Critical Code and Configuration Values
* **`au0828` USB Disconnect Bug (`drivers/media/usb/au0828/au0828-core.c`)**:
```c
static void au0828_usb_disconnect(struct usb_interface *interface)
{
struct au0828_dev *dev = usb_get_intfdata(interface);
...
if (au0828_analog_unregister(dev)) {
/* No need to call au0828_usb_release() if V4L2 is enabled */
return;
}
au0828_usb_release(dev);
}
```
* **`vusb_responses` Struct Alignment**:
Must provide all 17 fields when specifying a custom `generic` response to avoid parsing errors:
```
&AUTO={AUTO, &AUTO={0x20, 0x01, AUTO, "0000000000000000"}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
```
### 4. Potential Reasoning Loops / Repetitive Tool Calls
* **USB ID Patching**: Avoid using standard `usb_device_descriptor` structs for custom IDs, as syzkaller's Go code will patch them during generation/mutation. Use `ANY` blobs to force specific IDs.
* **String Literals**: Do not use raw `\x00` in syzkaller string arguments; use hex-encoded strings like `"0000000000000000"` for raw buffers.
Tokens:
input: 161437
output: 1619
thoughts: 821
|
| 353/2 |
2026/07/30 13:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 42254
output: 23
thoughts: 17
Thoughts: Okay, here's my summary, framed as my internal thought process:
**Diving into the Encoder Register**
Right, I'm deep in this code, and I've hit a point where I need to clarify something. Hang on... I need to track down a specific register. It's the `go7007_register_encoder`. That function name just screams "encoder configuration" to me. I need to understand what's happening within that function, what it's setting, and how it relates to the overall data flow. No point in just glossing over it. It's a critical piece of the puzzle, likely involved in how we're translating the input into the final output. Time to find that definition and see what secrets it holds.
|
| 354/2 |
2026/07/30 13:18 |
tool |
grepper |
0m
Args: map[Expression:go7007_register_encoder]
Results: map[Output:drivers/media/pci/saa7134/saa7134-go7007.c=405=static int saa7134_go7007_init(struct saa7134_dev *dev)
--
drivers/media/pci/saa7134/saa7134-go7007.c-450- * V4L2 and ALSA interfaces */
drivers/media/pci/saa7134/saa7134-go7007.c:451: if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0)
drivers/media/pci/saa7134/saa7134-go7007.c-452- goto allocfail;
--
drivers/media/usb/go7007/go7007-driver.c=227=static void go7007_remove(struct v4l2_device *v4l2_dev)
--
drivers/media/usb/go7007/go7007-driver.c-251- */
drivers/media/usb/go7007/go7007-driver.c:252:int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs)
drivers/media/usb/go7007/go7007-driver.c-253-{
--
drivers/media/usb/go7007/go7007-driver.c-314-}
drivers/media/usb/go7007/go7007-driver.c:315:EXPORT_SYMBOL(go7007_register_encoder);
drivers/media/usb/go7007/go7007-driver.c-316-
--
drivers/media/usb/go7007/go7007-priv.h=276=int go7007_reset_encoder(struct go7007 *go);
drivers/media/usb/go7007/go7007-priv.h:277:int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs);
drivers/media/usb/go7007/go7007-priv.h-278-int go7007_start_encoder(struct go7007 *go);
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1315- * V4L2 and ALSA interfaces */
drivers/media/usb/go7007/go7007-usb.c:1316: if (go7007_register_encoder(go, num_i2c_devs) < 0)
drivers/media/usb/go7007/go7007-usb.c-1317- goto allocfail;
]
|
| 355/2 |
2026/07/30 13:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 43274
output: 50
thoughts: 39
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Diving into the go7007 Encoder Registration**
Okay, time to dig into the go7007 driver again. I'm going to focus on the encoder registration process β specifically, `go7007_register_encoder` within `drivers/media/usb/go7007/go7007-driver.c`. I need to refresh my memory on how this device is introduced to the media framework. I'm especially curious about how the encoder capabilities are advertised and initialized within the kernel. I'll be looking for: how the device structures are populated, what flags and parameters are used during the registration, and how this links into the video4linux stack. I'll be watching to see how the driver handles initialization dependencies. I'm expecting to see calls to V4L2 functions for device registration and I'll pay attention to the error handling within this function to see how it manages potential issues during encoder setup. Finally, I'll be keeping a lookout for any proprietary extensions used by this driver.
|
| 356/2 |
2026/07/30 13:18 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-driver.c FirstLine:250 LineCount:100]
Results: map[Contents: 250: * Must NOT be called with the hw_lock held.
251: */
252: int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs)
253: {
254: int i, ret;
255:
256: dev_info(go->dev, "go7007: registering new %s\n", go->name);
257:
258: go->v4l2_dev.release = go7007_remove;
259: ret = v4l2_device_register(go->dev, &go->v4l2_dev);
260: if (ret < 0)
261: return ret;
262:
263: mutex_lock(&go->hw_lock);
264: ret = go7007_init_encoder(go);
265: mutex_unlock(&go->hw_lock);
266: if (ret < 0)
267: return ret;
268:
269: ret = go7007_v4l2_ctrl_init(go);
270: if (ret < 0)
271: return ret;
272:
273: if (!go->i2c_adapter_online &&
274: go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) {
275: ret = go7007_i2c_init(go);
276: if (ret < 0)
277: return ret;
278: go->i2c_adapter_online = 1;
279: }
280: if (go->i2c_adapter_online) {
281: if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) {
282: /* Reset the TW9906 */
283: go7007_write_addr(go, 0x3c82, 0x0009);
284: msleep(50);
285: go7007_write_addr(go, 0x3c82, 0x000d);
286: }
287: for (i = 0; i < num_i2c_devs; ++i)
288: init_i2c_module(&go->i2c_adapter, &go->board_info->i2c_devs[i]);
289:
290: if (go->tuner_type >= 0) {
291: struct tuner_setup setup = {
292: .addr = ADDR_UNSET,
293: .type = go->tuner_type,
294: .mode_mask = T_ANALOG_TV,
295: };
296:
297: v4l2_device_call_all(&go->v4l2_dev, 0, tuner,
298: s_type_addr, &setup);
299: }
300: if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
301: v4l2_subdev_call(go->sd_video, video, s_routing,
302: 0, 0, go->channel_number + 1);
303: }
304:
305: ret = go7007_v4l2_init(go);
306: if (ret < 0)
307: return ret;
308:
309: if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) {
310: go->audio_enabled = 1;
311: go7007_snd_init(go);
312: }
313: return 0;
314: }
315: EXPORT_SYMBOL(go7007_register_encoder);
316:
317: /*
318: * Send the encode firmware to the encoder, which will cause it
319: * to immediately start delivering the video and audio streams.
320: *
321: * Must be called with the hw_lock held.
322: */
323: int go7007_start_encoder(struct go7007 *go)
324: {
325: u8 *fw;
326: int fw_len, rv = 0, i, x, y;
327: u16 intr_val, intr_data;
328:
329: go->modet_enable = 0;
330: for (i = 0; i < 4; i++)
331: go->modet[i].enable = 0;
332:
333: switch (v4l2_ctrl_g_ctrl(go->modet_mode)) {
334: case V4L2_DETECT_MD_MODE_GLOBAL:
335: memset(go->modet_map, 0, sizeof(go->modet_map));
336: go->modet[0].enable = 1;
337: go->modet_enable = 1;
338: break;
339: case V4L2_DETECT_MD_MODE_REGION_GRID:
340: for (y = 0; y < go->height / 16; y++) {
341: for (x = 0; x < go->width / 16; x++) {
342: int idx = y * go->width / 16 + x;
343:
344: go->modet[go->modet_map[idx]].enable = 1;
345: }
346: }
347: go->modet_enable = 1;
348: break;
349: }
]
|
| 357/2 |
2026/07/30 13:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 45313
output: 53
thoughts: 170
Thoughts: **Analyzing the `go7007` Driver Initialization**
Okay, let's break this down. My initial thought is that `go7007_register_encoder` is calling `go7007_v4l2_init(go)`. That seems straightforward. But wait... if `go7007_v4l2_init` returns an error, let's say `ret` is less than zero, that triggers a failure. Then, the `go7007_usb_probe` function jumps straight to the `allocfail` label. And here's where it gets interesting: `allocfail` subsequently frees the `go` structure. But, didn't `go7007_register_encoder` already call `go7007_i2c_init(go)` *before* `go7007_v4l2_init`? And, inside `go7007_i2c_init`, `i2c_add_adapter` gets called! That potentially means we're adding an I2C adapter *before* we've validated the V4L2 initialization. This is a potential resource leak, or a premature deallocation problem! Therefore, I need to understand what's happening inside `go7007_v4l2_init` to determine the point of failure. I need to trace this more carefully.
|
| 358/2 |
2026/07/30 13:18 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-v4l2.c FirstLine:800 LineCount:100]
Results: map[Contents: 800: case V4L2_CID_MOTION_THRESHOLD2:
801: go->modet[2].motion_threshold = ctrl->val;
802: break;
803: case V4L2_CID_MB_THRESHOLD2:
804: go->modet[2].mb_threshold = ctrl->val;
805: break;
806: case V4L2_CID_PIXEL_THRESHOLD3:
807: go->modet[3].pixel_threshold = ctrl->val;
808: break;
809: case V4L2_CID_MOTION_THRESHOLD3:
810: go->modet[3].motion_threshold = ctrl->val;
811: break;
812: case V4L2_CID_MB_THRESHOLD3:
813: go->modet[3].mb_threshold = ctrl->val;
814: break;
815: case V4L2_CID_DETECT_MD_REGION_GRID:
816: mt = go->modet_map;
817: for (y = 0; y < go->height / 16; y++, mt += go->width / 16)
818: memcpy(mt, ctrl->p_new.p_u8 + y * (720 / 16), go->width / 16);
819: break;
820: default:
821: return -EINVAL;
822: }
823: return 0;
824: }
825:
826: static const struct v4l2_file_operations go7007_fops = {
827: .owner = THIS_MODULE,
828: .open = v4l2_fh_open,
829: .release = vb2_fop_release,
830: .unlocked_ioctl = video_ioctl2,
831: .read = vb2_fop_read,
832: .mmap = vb2_fop_mmap,
833: .poll = vb2_fop_poll,
834: };
835:
836: static const struct v4l2_ioctl_ops video_ioctl_ops = {
837: .vidioc_querycap = vidioc_querycap,
838: .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
839: .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
840: .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
841: .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
842: .vidioc_reqbufs = vb2_ioctl_reqbufs,
843: .vidioc_querybuf = vb2_ioctl_querybuf,
844: .vidioc_qbuf = vb2_ioctl_qbuf,
845: .vidioc_dqbuf = vb2_ioctl_dqbuf,
846: .vidioc_g_std = vidioc_g_std,
847: .vidioc_s_std = vidioc_s_std,
848: .vidioc_querystd = vidioc_querystd,
849: .vidioc_enum_input = vidioc_enum_input,
850: .vidioc_g_input = vidioc_g_input,
851: .vidioc_s_input = vidioc_s_input,
852: .vidioc_enumaudio = vidioc_enumaudio,
853: .vidioc_g_audio = vidioc_g_audio,
854: .vidioc_s_audio = vidioc_s_audio,
855: .vidioc_streamon = vb2_ioctl_streamon,
856: .vidioc_streamoff = vb2_ioctl_streamoff,
857: .vidioc_g_tuner = vidioc_g_tuner,
858: .vidioc_s_tuner = vidioc_s_tuner,
859: .vidioc_g_frequency = vidioc_g_frequency,
860: .vidioc_s_frequency = vidioc_s_frequency,
861: .vidioc_g_parm = vidioc_g_parm,
862: .vidioc_s_parm = vidioc_s_parm,
863: .vidioc_enum_framesizes = vidioc_enum_framesizes,
864: .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
865: .vidioc_log_status = vidioc_log_status,
866: .vidioc_subscribe_event = vidioc_subscribe_event,
867: .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
868: };
869:
870: static const struct video_device go7007_template = {
871: .name = "go7007",
872: .fops = &go7007_fops,
873: .release = video_device_release_empty,
874: .ioctl_ops = &video_ioctl_ops,
875: .tvnorms = V4L2_STD_ALL,
876: };
877:
878: static const struct v4l2_ctrl_ops go7007_ctrl_ops = {
879: .s_ctrl = go7007_s_ctrl,
880: };
881:
882: static const struct v4l2_ctrl_config go7007_pixel_threshold0_ctrl = {
883: .ops = &go7007_ctrl_ops,
884: .id = V4L2_CID_PIXEL_THRESHOLD0,
885: .name = "Pixel Threshold Region 0",
886: .type = V4L2_CTRL_TYPE_INTEGER,
887: .def = 20,
888: .max = 32767,
889: .step = 1,
890: };
891:
892: static const struct v4l2_ctrl_config go7007_motion_threshold0_ctrl = {
893: .ops = &go7007_ctrl_ops,
894: .id = V4L2_CID_MOTION_THRESHOLD0,
895: .name = "Motion Threshold Region 0",
896: .type = V4L2_CTRL_TYPE_INTEGER,
897: .def = 80,
898: .max = 32767,
899: .step = 1,
]
|
| 359/2 |
2026/07/30 13:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 47826
output: 54
thoughts: 20
Thoughts: Here's my thought process, summarized as you requested:
**Deconstructing the Initialization**
Okay, hold on a second. Before I proceed, I need to get a handle on this. I'm seeing something mentioned here, `go7007_v4l2_init`. I need to understand what this function does. This is critical. It's likely the starting point for initializing the V4L2 interface for this `go7007` device. I can't build any further understanding or plan my next steps until I comprehend how the device itself is brought online from the driver's perspective. I need to trace its inputs, outputs, and any important side effects before anything else. This init function is the cornerstone.
|
| 360/2 |
2026/07/30 13:18 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-v4l2.c FirstLine:1100 LineCount:100]
Results: map[Contents:1100: v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD);
1101: if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) {
1102: v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY);
1103: v4l2_disable_ioctl(vdev, VIDIOC_G_FREQUENCY);
1104: v4l2_disable_ioctl(vdev, VIDIOC_S_TUNER);
1105: v4l2_disable_ioctl(vdev, VIDIOC_G_TUNER);
1106: } else {
1107: struct v4l2_frequency f = {
1108: .type = V4L2_TUNER_ANALOG_TV,
1109: .frequency = 980,
1110: };
1111:
1112: call_all(&go->v4l2_dev, tuner, s_frequency, &f);
1113: }
1114: if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV)) {
1115: v4l2_disable_ioctl(vdev, VIDIOC_G_STD);
1116: v4l2_disable_ioctl(vdev, VIDIOC_S_STD);
1117: vdev->tvnorms = 0;
1118: }
1119: if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING)
1120: v4l2_disable_ioctl(vdev, VIDIOC_ENUM_FRAMESIZES);
1121: if (go->board_info->num_aud_inputs == 0) {
1122: v4l2_disable_ioctl(vdev, VIDIOC_G_AUDIO);
1123: v4l2_disable_ioctl(vdev, VIDIOC_S_AUDIO);
1124: v4l2_disable_ioctl(vdev, VIDIOC_ENUMAUDIO);
1125: }
1126: /* Setup correct crystal frequency on this board */
1127: if (go->board_info->sensor_flags & GO7007_SENSOR_SAA7115)
1128: v4l2_subdev_call(go->sd_video, video, s_crystal_freq,
1129: SAA7115_FREQ_24_576_MHZ,
1130: SAA7115_FREQ_FL_APLL | SAA7115_FREQ_FL_UCGC |
1131: SAA7115_FREQ_FL_DOUBLE_ASCLK);
1132: go7007_s_input(go);
1133: if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
1134: go7007_s_std(go);
1135: rv = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
1136: if (rv < 0)
1137: return rv;
1138: dev_info(go->dev, "registered device %s [v4l2]\n",
1139: video_device_node_name(vdev));
1140:
1141: return 0;
1142: }
1143:
1144: void go7007_v4l2_remove(struct go7007 *go)
1145: {
1146: v4l2_ctrl_handler_free(&go->hdl);
1147: }
]
|
| 361/2 |
2026/07/30 13:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 49052
output: 53
thoughts: 22
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Debugging Initiative: Function Placement**
Okay, so I'm digging through this `go7007_v4l2` code, and I'm looking at the initialization sequence. I thought I had a handle on the flow, but I need to re-evaluate where I'm at. I thought it was earlier, but wait, looking at the code, `go7007_v4l2_init` isn't where I expected it. I'm going to quickly re-scan this file and double-check its location. I need to pinpoint the *exact* spot of this function. That is essential for understanding how the driver's underlying structures are set up. I need to see when, exactly, it's called and by what other parts of the driver. I need to make sure I'm following the correct execution path. I will need to trace back from this function call to its callers to understand how the driver's fundamental structures are set up, and make sure that it all makes logical sense.
|
| 362/2 |
2026/07/30 13:18 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-v4l2.c FirstLine:1040 LineCount:60]
Results: map[Contents:1040: v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold0_ctrl, NULL);
1041: v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold0_ctrl, NULL);
1042: v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold0_ctrl, NULL);
1043: v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold1_ctrl, NULL);
1044: v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold1_ctrl, NULL);
1045: v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold1_ctrl, NULL);
1046: v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold2_ctrl, NULL);
1047: v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold2_ctrl, NULL);
1048: v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold2_ctrl, NULL);
1049: v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold3_ctrl, NULL);
1050: v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold3_ctrl, NULL);
1051: v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold3_ctrl, NULL);
1052: v4l2_ctrl_new_custom(hdl, &go7007_mb_regions_ctrl, NULL);
1053: go->modet_mode = v4l2_ctrl_new_std_menu(hdl, NULL,
1054: V4L2_CID_DETECT_MD_MODE,
1055: V4L2_DETECT_MD_MODE_REGION_GRID,
1056: 1 << V4L2_DETECT_MD_MODE_THRESHOLD_GRID,
1057: V4L2_DETECT_MD_MODE_DISABLED);
1058: if (hdl->error) {
1059: int rv = hdl->error;
1060:
1061: v4l2_err(&go->v4l2_dev, "Could not register controls\n");
1062: return rv;
1063: }
1064: go->v4l2_dev.ctrl_handler = hdl;
1065: return 0;
1066: }
1067:
1068: int go7007_v4l2_init(struct go7007 *go)
1069: {
1070: struct video_device *vdev = &go->vdev;
1071: int rv;
1072:
1073: mutex_init(&go->serialize_lock);
1074: mutex_init(&go->queue_lock);
1075:
1076: INIT_LIST_HEAD(&go->vidq_active);
1077: go->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1078: go->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1079: go->vidq.ops = &go7007_video_qops;
1080: go->vidq.mem_ops = &vb2_vmalloc_memops;
1081: go->vidq.drv_priv = go;
1082: go->vidq.buf_struct_size = sizeof(struct go7007_buffer);
1083: go->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1084: go->vidq.lock = &go->queue_lock;
1085: rv = vb2_queue_init(&go->vidq);
1086: if (rv)
1087: return rv;
1088: *vdev = go7007_template;
1089: vdev->lock = &go->serialize_lock;
1090: vdev->queue = &go->vidq;
1091: vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
1092: V4L2_CAP_STREAMING;
1093: if (go->board_info->num_aud_inputs)
1094: vdev->device_caps |= V4L2_CAP_AUDIO;
1095: if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
1096: vdev->device_caps |= V4L2_CAP_TUNER;
1097: video_set_drvdata(vdev, go);
1098: vdev->v4l2_dev = &go->v4l2_dev;
1099: if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd))
]
|
| 363/2 |
2026/07/30 13:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 50792
output: 50
thoughts: 1102
Thoughts: **Analyzing the GO7007 USB Probe Function**
Okay, let's break this down systematically. I'm starting with `go7007_usb_probe` and its potential failure points. My initial thought is that the call to `video_register_device` within `go7007_v4l2_init` could fail. If that fails, it returns a negative value, `rv`, and `go7007_usb_probe` should then jump to `allocfail`. So, the question is, what can make `video_register_device` fail? Running out of minor numbers is possible, but not typical.
But hold on, what if `go7007_v4l2_init` doesn't actually fail immediately? Maybe a later call within `go7007_register_encoder` fails instead? The code does call `go7007_snd_init`, but its return value is ignored. Therefore, `go7007_register_encoder` *won't* fail after `go7007_v4l2_init` because of the audio init. This means `go7007_v4l2_init` itself must be the problem.
Alright, so how can `go7007_v4l2_init` fail? The initialization of `vb2_queue_init` could fail if `go->vidq` is invalid, but that seems unlikely as it's hardcoded. However, `video_register_device` could still fail from the V4L2 init code, but that is rare.
Let's focus on whether `go7007_usb_probe` can fail AFTER the `go7007_register_encoder` call. The code shows no failure points after that function returns 0.
So, could `go7007_register_encoder` fail BEFORE `go7007_v4l2_init`? It looks like we have a branch. First, there's a call to `go7007_i2c_init`, which could fail. Then it seems there are multiple calls based on the board, but they seem mostly setup-based, so I'll need to dig deeper. The next significant point is that `init_i2c_module` calls `v4l2_i2c_new_subdev`. If `go7007_v4l2_init` fails, it returns a negative value. But how to *make* it fail? And where else could `go7007_usb_probe` potentially fail? Let's go back and re-examine the `go7007_usb_probe` function.
|
| 364/2 |
2026/07/30 13:18 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1260 LineCount:50]
Results: map[Contents:1260: }
1261: }
1262:
1263: /* Print a nasty message if the user attempts to use a USB2.0 device in
1264: * a USB1.1 port. There will be silent corruption of the stream. */
1265: if ((board->flags & GO7007_USB_EZUSB) &&
1266: usbdev->speed != USB_SPEED_HIGH)
1267: dev_err(go->dev, "*** WARNING *** This device must be connected to a USB 2.0 port! Attempting to capture video through a USB 1.1 port will result in stream corruption, even at low bitrates!\n");
1268:
1269: /* Allocate the URBs and buffers for receiving the video stream */
1270: if (board->flags & GO7007_USB_EZUSB) {
1271: if (!usb->usbdev->ep_in[6])
1272: goto allocfail;
1273: v_urb_len = 1024;
1274: video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);
1275: } else {
1276: if (!usb->usbdev->ep_in[1])
1277: goto allocfail;
1278: v_urb_len = 512;
1279: video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
1280: }
1281: for (i = 0; i < 8; ++i) {
1282: usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
1283: if (usb->video_urbs[i] == NULL)
1284: goto allocfail;
1285: usb->video_urbs[i]->transfer_buffer =
1286: kmalloc(v_urb_len, GFP_KERNEL);
1287: if (usb->video_urbs[i]->transfer_buffer == NULL)
1288: goto allocfail;
1289: usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
1290: usb->video_urbs[i]->transfer_buffer, v_urb_len,
1291: go7007_usb_read_video_pipe_complete, go);
1292: }
1293:
1294: /* Allocate the URBs and buffers for receiving the audio stream */
1295: if ((board->flags & GO7007_USB_EZUSB) &&
1296: (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) {
1297: if (!usb->usbdev->ep_in[8])
1298: goto allocfail;
1299: for (i = 0; i < 8; ++i) {
1300: usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
1301: if (usb->audio_urbs[i] == NULL)
1302: goto allocfail;
1303: usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,
1304: GFP_KERNEL);
1305: if (usb->audio_urbs[i]->transfer_buffer == NULL)
1306: goto allocfail;
1307: usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,
1308: usb_rcvbulkpipe(usb->usbdev, 8),
1309: usb->audio_urbs[i]->transfer_buffer, 4096,
]
|
| 365/2 |
2026/07/30 13:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 53543
output: 50
thoughts: 55
Thoughts: Here's my take on the thought process:
**Diving into the go7007 USB Probe Function**
Okay, so the `go7007_usb_probe` function is calling `i2c_add_adapter` under a specific condition. I need to understand that logic. The code says it's happening when `board->flags` has the `GO7007_USB_EZUSB_I2C` flag set. That's my starting point. Now I need to trace this back and see exactly *where* it's calling `i2c_add_adapter` in that conditional. Let's dig in and figure out the exact location and context of this call. Gotta get the full picture here.
|
| 366/2 |
2026/07/30 13:18 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1130 LineCount:50]
Results: map[Contents:1130: go->hpi_ops = &go7007_usb_ezusb_hpi_ops;
1131: else
1132: go->hpi_ops = &go7007_usb_onboard_hpi_ops;
1133: go->hpi_context = usb;
1134:
1135: ep = usb->usbdev->ep_in[4];
1136: if (!ep)
1137: goto allocfail;
1138:
1139: /* Allocate the URB and buffer for receiving incoming interrupts */
1140: usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
1141: if (usb->intr_urb == NULL)
1142: goto allocfail;
1143: usb->intr_urb->transfer_buffer = kmalloc_array(2, sizeof(u16),
1144: GFP_KERNEL);
1145: if (usb->intr_urb->transfer_buffer == NULL)
1146: goto allocfail;
1147:
1148: if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK)
1149: usb_fill_bulk_urb(usb->intr_urb, usb->usbdev,
1150: usb_rcvbulkpipe(usb->usbdev, 4),
1151: usb->intr_urb->transfer_buffer, 2*sizeof(u16),
1152: go7007_usb_readinterrupt_complete, go);
1153: else
1154: usb_fill_int_urb(usb->intr_urb, usb->usbdev,
1155: usb_rcvintpipe(usb->usbdev, 4),
1156: usb->intr_urb->transfer_buffer, 2*sizeof(u16),
1157: go7007_usb_readinterrupt_complete, go, 8);
1158: usb_set_intfdata(intf, &go->v4l2_dev);
1159:
1160: /* Boot the GO7007 */
1161: if (go7007_boot_encoder(go, go->board_info->flags &
1162: GO7007_BOARD_USE_ONBOARD_I2C) < 0)
1163: goto allocfail;
1164:
1165: /* Register the EZ-USB I2C adapter, if we're using it */
1166: if (board->flags & GO7007_USB_EZUSB_I2C) {
1167: memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
1168: sizeof(go7007_usb_adap_templ));
1169: mutex_init(&usb->i2c_lock);
1170: go->i2c_adapter.dev.parent = go->dev;
1171: i2c_set_adapdata(&go->i2c_adapter, go);
1172: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
1173: dev_err(go->dev, "error: i2c_add_adapter failed\n");
1174: goto allocfail;
1175: }
1176: go->i2c_adapter_online = 1;
1177: }
1178:
1179: /* Pelco and Adlink reused the XMen and XMen-III vendor and product
]
|
| 367/2 |
2026/07/30 13:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 54786
output: 28
thoughts: 74
Thoughts: Okay, here's my take on those thoughts, framed as my own mental processing:
**USB and I2C - Not Quite What I Expected**
Right, *that* bit of code, `board->flags & GO7007_USB_EZUSB_I2C`... ah, yes, I'm trying to figure out if we're dealing with a specific I2C configuration. Hang on a second... wait, isn't `XMEN` supposed to *not* have that `GO7007_USB_EZUSB_I2C` flag set? Something's not lining up. Okay, better double-check the board definitions. I need to quickly identify which boards *actually* use that particular configuration, just to be sure I haven't missed something fundamental in the setup. Let's see... back to the source...
|
| 368/2 |
2026/07/30 13:18 |
tool |
grepper |
0m
Args: map[Expression:GO7007_USB_EZUSB_I2C]
Results: map[Output:drivers/media/usb/go7007/go7007-usb.c=26=MODULE_PARM_DESC(assume_endura,
--
drivers/media/usb/go7007/go7007-usb.c-45-#define GO7007_USB_EZUSB (1<<0)
drivers/media/usb/go7007/go7007-usb.c:46:#define GO7007_USB_EZUSB_I2C (1<<1)
drivers/media/usb/go7007/go7007-usb.c-47-
--
drivers/media/usb/go7007/go7007-usb.c=141=static const struct go7007_usb_board board_star_trek = {
drivers/media/usb/go7007/go7007-usb.c:142: .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
drivers/media/usb/go7007/go7007-usb.c-143- .main_info = {
--
drivers/media/usb/go7007/go7007-usb.c=188=static const struct go7007_usb_board board_px_tv402u = {
drivers/media/usb/go7007/go7007-usb.c:189: .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
drivers/media/usb/go7007/go7007-usb.c-190- .main_info = {
--
drivers/media/usb/go7007/go7007-usb.c=418=static const struct go7007_usb_board board_sensoray_2250 = {
drivers/media/usb/go7007/go7007-usb.c:419: .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
drivers/media/usb/go7007/go7007-usb.c-420- .main_info = {
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1165- /* Register the EZ-USB I2C adapter, if we're using it */
drivers/media/usb/go7007/go7007-usb.c:1166: if (board->flags & GO7007_USB_EZUSB_I2C) {
drivers/media/usb/go7007/go7007-usb.c-1167- memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
]
|
| 369/2 |
2026/07/30 13:18 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 55874
output: 49
thoughts: 727
Thoughts: **The I2C Adapter Bug in GO7007 USB Drivers**
Okay, so I've spotted something interesting. `board_star_trek`, `board_px_tv402u`, and `board_sensoray_2250` all seem to utilize the `GO7007_USB_EZUSB_I2C` feature. Let's focus on `board_px_tv402u` for a closer look and reference the `go7007_usb_id_table`. Based on this, it looks like if we emulate the USB device IDs `0x093b:0xa104` with a `bcdDevice` value of `0x1`, the driver will associate it with `board_px_tv402u`.
Now, if we dive into the `go7007_usb_probe` function for `board_px_tv402u`, it's all starting to click. I see that if `GO7007_USB_EZUSB_I2C` is set, an I2C adapter is initialized and added. Crucially, the code then checks for the tuner model, specifically calling `go7007_usb_vendor_request`.
Aha! Here's the potential problem. If `go7007_usb_vendor_request` fails β let's say due to a missing response (more on that later) β the code jumps directly to `allocfail`. The critical detail is that `allocfail` frees the `go` structure *without* unregistering the I2C adapter!
This is it! It's a classic resource leak, a textbook example of an I2C adapter that's left dangling. And the culprit is right there, the vendor request.
The missing piece is `go7007_usb_vendor_request` itself, which, as I see it, sends a control message and expects a response. If no response is provided, it will, of course, fail. So, if we can reliably trigger a failure here, we can trigger the bug!
|
| 370/2 |
2026/07/30 13:19 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:850 LineCount:50]
Results: map[Contents: 850: goto audio_submit_failed;
851: }
852: }
853: return 0;
854:
855: audio_submit_failed:
856: for (i = 0; i < 7; ++i)
857: usb_kill_urb(usb->audio_urbs[i]);
858: video_submit_failed:
859: for (i = 0; i < 8; ++i)
860: usb_kill_urb(usb->video_urbs[i]);
861: return -1;
862: }
863:
864: static int go7007_usb_stream_stop(struct go7007 *go)
865: {
866: struct go7007_usb *usb = go->hpi_context;
867: int i;
868:
869: if (go->status == STATUS_SHUTDOWN)
870: return 0;
871: for (i = 0; i < 8; ++i)
872: usb_kill_urb(usb->video_urbs[i]);
873: if (go->audio_enabled)
874: for (i = 0; i < 8; ++i)
875: usb_kill_urb(usb->audio_urbs[i]);
876: return 0;
877: }
878:
879: static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len)
880: {
881: struct go7007_usb *usb = go->hpi_context;
882: int transferred, pipe;
883: int timeout = 500;
884:
885: pr_debug("DownloadBuffer sending %d bytes\n", len);
886:
887: if (usb->board->flags & GO7007_USB_EZUSB)
888: pipe = usb_sndbulkpipe(usb->usbdev, 2);
889: else
890: pipe = usb_sndbulkpipe(usb->usbdev, 3);
891:
892: return usb_bulk_msg(usb->usbdev, pipe, data, len,
893: &transferred, timeout);
894: }
895:
896: static void go7007_usb_release(struct go7007 *go)
897: {
898: struct go7007_usb *usb = go->hpi_context;
899: struct urb *vurb, *aurb;
]
|
| 371/2 |
2026/07/30 13:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 57899
output: 25
thoughts: 21
Thoughts: Here's my thought process, as requested:
**Navigating the Codebase**
Okay, so I'm digging into this code, trying to understand the flow, and I just noticed something that's making my brain itch. I was expecting `go7007_usb_vendor_request` to be somewhere, but I'm backtracking through the file. It looks like it's defined much earlier than I initially thought. This means I need to adjust my mental map of how the function calls are made within this section of code, and make sure that I understand how the early declaration impacts subsequent function calls. I should make sure I have the proper call order documented in my notes.
|
| 372/2 |
2026/07/30 13:19 |
tool |
grepper |
0m
Args: map[Expression:go7007_usb_vendor_request]
Results: map[Output:drivers/media/usb/go7007/go7007-usb.c=618=MODULE_DEVICE_TABLE(usb, go7007_usb_id_table);
--
drivers/media/usb/go7007/go7007-usb.c-621-
drivers/media/usb/go7007/go7007-usb.c:622:static int go7007_usb_vendor_request(struct go7007 *go, int request,
drivers/media/usb/go7007/go7007-usb.c-623- int value, int index, void *transfer_buffer, int length, int in)
--
drivers/media/usb/go7007/go7007-usb.c=641=static int go7007_usb_interface_reset(struct go7007 *go)
--
drivers/media/usb/go7007/go7007-usb.c-655- pr_debug("resetting EZ-USB buffers\n");
drivers/media/usb/go7007/go7007-usb.c:656: if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 ||
drivers/media/usb/go7007/go7007-usb.c:657: go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0)
drivers/media/usb/go7007/go7007-usb.c-658- return -1;
--
drivers/media/usb/go7007/go7007-usb.c=949=static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter,
--
drivers/media/usb/go7007/go7007-usb.c-1001- }
drivers/media/usb/go7007/go7007-usb.c:1002: if (go7007_usb_vendor_request(go, 0x24, 0, 0,
drivers/media/usb/go7007/go7007-usb.c-1003- buf, buf_len, 0) < 0)
--
drivers/media/usb/go7007/go7007-usb.c-1006- memset(buf, 0, msgs[i].len + 1);
drivers/media/usb/go7007/go7007-usb.c:1007: if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf,
drivers/media/usb/go7007/go7007-usb.c-1008- msgs[i].len + 1, 1) < 0)
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1224- /* Board strapping indicates tuner model */
drivers/media/usb/go7007/go7007-usb.c:1225: if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3,
drivers/media/usb/go7007/go7007-usb.c-1226- 1) < 0) {
--
drivers/media/usb/go7007/go7007-usb.c-1255- * to the EZ-USB GPIO output pins */
drivers/media/usb/go7007/go7007-usb.c:1256: if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
drivers/media/usb/go7007/go7007-usb.c-1257- NULL, 0, 0) < 0) {
--
drivers/media/usb/go7007/s2250-board.c=125=static inline struct s2250 *to_state(struct v4l2_subdev *sd)
--
drivers/media/usb/go7007/s2250-board.c-130-/* from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/
drivers/media/usb/go7007/s2250-board.c:131:static int go7007_usb_vendor_request(struct go7007 *go, u16 request,
drivers/media/usb/go7007/s2250-board.c-132- u16 value, u16 index, void *transfer_buffer, int length, int in)
--
drivers/media/usb/go7007/s2250-board.c=151=static int write_reg(struct i2c_client *client, u8 reg, u8 value)
--
drivers/media/usb/go7007/s2250-board.c-174- }
drivers/media/usb/go7007/s2250-board.c:175: rc = go7007_usb_vendor_request(go, 0x55, dev_addr,
drivers/media/usb/go7007/s2250-board.c-176- (reg<<8 | value),
--
drivers/media/usb/go7007/s2250-board.c=185=static int write_reg_fp(struct i2c_client *client, u16 addr, u16 val)
--
drivers/media/usb/go7007/s2250-board.c-213- }
drivers/media/usb/go7007/s2250-board.c:214: rc = go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1);
drivers/media/usb/go7007/s2250-board.c-215- mutex_unlock(&usb->i2c_lock);
--
drivers/media/usb/go7007/s2250-board.c=249=static int read_reg_fp(struct i2c_client *client, u16 addr, u16 *val)
--
drivers/media/usb/go7007/s2250-board.c-275- }
drivers/media/usb/go7007/s2250-board.c:276: rc = go7007_usb_vendor_request(go, 0x58, addr, 0, buf, 16, 1);
drivers/media/usb/go7007/s2250-board.c-277- mutex_unlock(&usb->i2c_lock);
--
drivers/media/usb/go7007/s2250-board.c=497=static int s2250_probe(struct i2c_client *client)
--
drivers/media/usb/go7007/s2250-board.c-572- if (data != NULL) {
drivers/media/usb/go7007/s2250-board.c:573: int rc = go7007_usb_vendor_request(go, 0x41, 0, 0,
drivers/media/usb/go7007/s2250-board.c-574- data, 16, 1);
--
drivers/media/usb/go7007/s2250-board.c-582- data[1] |= mask;
drivers/media/usb/go7007/s2250-board.c:583: go7007_usb_vendor_request(go, 0x40, 0,
drivers/media/usb/go7007/s2250-board.c-584- (data[1]<<8)
]
|
| 373/2 |
2026/07/30 13:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 60292
output: 49
thoughts: 997
Thoughts: **Analyzing the USB Vendor Request Vulnerability**
Okay, so I'm looking at this `go7007_usb_vendor_request` function, and it uses `usb_control_msg`. Right, that's standard for vendor-specific requests over USB control pipes. The key here is that if `usb_control_msg` doesn't get a proper response, it'll fail, returning a negative error code.
Now, I remember syzkaller's `syz_usb_connect` system call can inject responses through the `vusb_responses` struct. If we don't provide any responses, or the provided response indicates failure, that `go7007_usb_vendor_request` call will bomb out. Wait, even if the array is empty, which means no responses!
So, the trick to reproducing this is crafting a `syz_usb_connect` call and making sure it *doesn't* supply a valid response to the vendor request. Let's see... Vendor ID is `0x093b`, Product ID is `0xa104`. I'll need to construct the device descriptor and other descriptors, too.
Device descriptor is: `12 01 00 02 00 00 00 40 3b 09 04 a1 01 00 00 00 00 01`. Quick sanity check: `bcdDevice` should be `0x0001`, so `01 00`... looks good. Config descriptor: `09 02 22 00 01 01 00 80 00`. Interface descriptor: `09 04 00 00 03 ff 00 ff 00`.
Okay, next I need to look at the board flags. The `board_px_tv402u` has `GO7007_USB_EZUSB` flag, which is important because it is using `ep_in[6]` for video, `ep_in[8]` for audio, and `ep_in[4]` for interrupts. Actually, the code checks `ep_in[4]` first. If that endpoint is not provided it goes to `allocfail`, and the I2C adapter is NOT created!
If `ep_in[4]` is missing, the driver will go to `allocfail`. The `ep_in[4]` check happens *before* the I2C adapter registration with `i2c_add_adapter`. So we *must* provide `ep_in[4]` to avoid that. Same with the boot process of the encoder through `go7007_boot_encoder`! It is also called before the I2C adapter.
Let's check `go7007_boot_encoder`.
|
| 374/2 |
2026/07/30 13:19 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-driver.c FirstLine:120 LineCount:50]
Results: map[Contents: 120:
121: /*
122: * Boot the encoder and register the I2C adapter if requested. Do the
123: * minimum initialization necessary, since the board-specific code may
124: * still need to probe the board ID.
125: *
126: * Must NOT be called with the hw_lock held.
127: */
128: int go7007_boot_encoder(struct go7007 *go, int init_i2c)
129: {
130: int ret;
131:
132: mutex_lock(&go->hw_lock);
133: ret = go7007_load_encoder(go);
134: mutex_unlock(&go->hw_lock);
135: if (ret < 0)
136: return -1;
137: if (!init_i2c)
138: return 0;
139: if (go7007_i2c_init(go) < 0)
140: return -1;
141: go->i2c_adapter_online = 1;
142: return 0;
143: }
144: EXPORT_SYMBOL(go7007_boot_encoder);
145:
146: /*
147: * Configure any hardware-related registers in the GO7007, such as GPIO
148: * pins and bus parameters, which are board-specific. This assumes
149: * the boot firmware has already been downloaded.
150: *
151: * Must be called with the hw_lock held.
152: */
153: static int go7007_init_encoder(struct go7007 *go)
154: {
155: if (go->board_info->audio_flags & GO7007_AUDIO_I2S_MASTER) {
156: go7007_write_addr(go, 0x1000, 0x0811);
157: go7007_write_addr(go, 0x1000, 0x0c11);
158: }
159: switch (go->board_id) {
160: case GO7007_BOARDID_MATRIX_REV:
161: /* Set GPIO pin 0 to be an output (audio clock control) */
162: go7007_write_addr(go, 0x3c82, 0x0001);
163: go7007_write_addr(go, 0x3c80, 0x00fe);
164: break;
165: case GO7007_BOARDID_ADLINK_MPG24:
166: /* set GPIO5 to be an output, currently low */
167: go7007_write_addr(go, 0x3c82, 0x0000);
168: go7007_write_addr(go, 0x3c80, 0x00df);
169: break;
]
|
| 375/2 |
2026/07/30 13:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 62874
output: 48
thoughts: 25
Thoughts: Here's my take on the thought process, as if it were my own:
**Connecting the Dots in the Encoding Process**
Okay, let me see... I'm tracing the execution flow of this encoder function, and something just clicked. I see that `go7007_boot_encoder` is calling `go7007_load_encoder`. Now, the implications of that are pretty clear in my mind. `go7007_boot_encoder` is acting as the entry point, the initialization stage, and it's *directly* leveraging `go7007_load_encoder`. That means `load_encoder` must be handling the critical low-level initialization. It is likely that `load_encoder` pulls in any critical settings such as the codec type, bitrate, and resolution settings that are likely required for correct execution. The boot function is probably just the wrapper function. It all makes logical sense, but having the pieces connected this quickly is satisfying. It suggests a well-structured and probably efficient workflow. This calls for a closer look at the interaction between these two functions β I need to dig into what data is passed between them and how the bootstrapping is handled. It could be some vital information about the setup of the internal encoder modules. This could be a good starting point for optimization or debugging, depending on what I find.
|
| 376/2 |
2026/07/30 13:19 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-driver.c FirstLine:60 LineCount:50]
Results: map[Contents: 60:
61: if (go7007_write_interrupt(go, 0x0010, addr) < 0)
62: return -EIO;
63: while (count-- > 0) {
64: if (go7007_read_interrupt(go, &value, data) == 0 &&
65: value == 0xa000)
66: return 0;
67: }
68: return -EIO;
69: }
70: EXPORT_SYMBOL(go7007_read_addr);
71:
72: /*
73: * Send the boot firmware to the encoder, which just wakes it up and lets
74: * us talk to the GPIO pins and on-board I2C adapter.
75: *
76: * Must be called with the hw_lock held.
77: */
78: static int go7007_load_encoder(struct go7007 *go)
79: {
80: const struct firmware *fw_entry;
81: char fw_name[] = "go7007/go7007fw.bin";
82: void *bounce;
83: int fw_len;
84: u16 intr_val, intr_data;
85:
86: if (go->boot_fw == NULL) {
87: if (request_firmware(&fw_entry, fw_name, go->dev)) {
88: v4l2_err(go, "unable to load firmware from file \"%s\"\n", fw_name);
89: return -1;
90: }
91: if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) {
92: v4l2_err(go, "file \"%s\" does not appear to be go7007 firmware\n", fw_name);
93: release_firmware(fw_entry);
94: return -1;
95: }
96: fw_len = fw_entry->size - 16;
97: bounce = kmemdup(fw_entry->data + 16, fw_len, GFP_KERNEL);
98: if (bounce == NULL) {
99: v4l2_err(go, "unable to allocate %d bytes for firmware transfer\n", fw_len);
100: release_firmware(fw_entry);
101: return -1;
102: }
103: release_firmware(fw_entry);
104: go->boot_fw_len = fw_len;
105: go->boot_fw = bounce;
106: }
107: if (go7007_interface_reset(go) < 0 ||
108: go7007_send_firmware(go, go->boot_fw, go->boot_fw_len) < 0 ||
109: go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
]
|
| 377/2 |
2026/07/30 13:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 64106
output: 50
thoughts: 758
Thoughts: **Debugging a Potential Use-After-Free in the GO7007 Driver**
Okay, let's break this down. It looks like `go7007_load_encoder` calls `request_firmware`, and if that fails, we get a `-1` and the whole probe function should short-circuit. Specifically, if `request_firmware` fails, then `go7007_boot_encoder` returns `-1`, and the probe goes to `allocfail` before `i2c_add_adapter` is even called, so no UAF.
However, the key is syzkaller. Because the firmware might not be present in the syzkaller environment, I initially thought the failure of `request_firmware` would be the common case. But the bug report is clear: we have a UAF, so `i2c_add_adapter` *was* called. How did that happen if the firmware wasn't loaded?
Hold on... maybe `go7007_boot_encoder` isn't the only entry point to `i2c_add_adapter`. Let's think about the `XMEN` board. It has `GO7007_BOARD_USE_ONBOARD_I2C`. If we use this board, then `go7007_boot_encoder` calls `go7007_i2c_init`. Looking at the code, if `init_i2c` is true, then we call `go7007_i2c_init`. In the XMEN case, this is `TRUE`!
Now, the important part: `go7007_boot_encoder` calls `go7007_load_encoder` *first*. If `go7007_load_encoder` fails due to a missing firmware, it returns before even calling `go7007_i2c_init`, and thus no `i2c_add_adapter`! So the UAF still shouldn't happen. The only place where `i2c_add_adapter` is called is in the `go7007_usb_probe` function.
I need to look for any other places in the driver where `i2c_add_adapter` is called. Let's start with `go7007_usb_probe` and its relationships with the `go7007_load_encoder` and `go7007_boot_encoder` functions, to check the sequence of calls.
|
| 378/2 |
2026/07/30 13:19 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1150 LineCount:50]
Results: map[Contents:1150: usb_rcvbulkpipe(usb->usbdev, 4),
1151: usb->intr_urb->transfer_buffer, 2*sizeof(u16),
1152: go7007_usb_readinterrupt_complete, go);
1153: else
1154: usb_fill_int_urb(usb->intr_urb, usb->usbdev,
1155: usb_rcvintpipe(usb->usbdev, 4),
1156: usb->intr_urb->transfer_buffer, 2*sizeof(u16),
1157: go7007_usb_readinterrupt_complete, go, 8);
1158: usb_set_intfdata(intf, &go->v4l2_dev);
1159:
1160: /* Boot the GO7007 */
1161: if (go7007_boot_encoder(go, go->board_info->flags &
1162: GO7007_BOARD_USE_ONBOARD_I2C) < 0)
1163: goto allocfail;
1164:
1165: /* Register the EZ-USB I2C adapter, if we're using it */
1166: if (board->flags & GO7007_USB_EZUSB_I2C) {
1167: memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
1168: sizeof(go7007_usb_adap_templ));
1169: mutex_init(&usb->i2c_lock);
1170: go->i2c_adapter.dev.parent = go->dev;
1171: i2c_set_adapdata(&go->i2c_adapter, go);
1172: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
1173: dev_err(go->dev, "error: i2c_add_adapter failed\n");
1174: goto allocfail;
1175: }
1176: go->i2c_adapter_online = 1;
1177: }
1178:
1179: /* Pelco and Adlink reused the XMen and XMen-III vendor and product
1180: * IDs for their own incompatible designs. We can detect XMen boards
1181: * by probing the sensor, but there is no way to probe the sensors on
1182: * the Pelco and Adlink designs so we default to the Adlink. If it
1183: * is actually a Pelco, the user must set the assume_endura module
1184: * parameter. */
1185: if ((go->board_id == GO7007_BOARDID_XMEN ||
1186: go->board_id == GO7007_BOARDID_XMEN_III) &&
1187: go->i2c_adapter_online) {
1188: union i2c_smbus_data data;
1189:
1190: /* Check to see if register 0x0A is 0x76 */
1191: i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,
1192: I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);
1193: if (data.byte != 0x76) {
1194: if (assume_endura) {
1195: go->board_id = GO7007_BOARDID_ENDURA;
1196: usb->board = board = &board_endura;
1197: go->board_info = &board->main_info;
1198: strscpy(go->name, "Pelco Endura",
1199: sizeof(go->name));
]
|
| 379/2 |
2026/07/30 13:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 66529
output: 48
thoughts: 785
Thoughts: **Analyzing the Debug Output**
Okay, let's break this down. It looks like `go7007_boot_encoder` is consistently called *before* `i2c_add_adapter`, whether we're talking about the `EZUSB_I2C` or the `ONBOARD_I2C` scenario. And, crucially, `go7007_boot_encoder` ultimately calls `go7007_load_encoder`, which in turn, calls `request_firmware`. If that `request_firmware` fails, `go7007_boot_encoder` returns -1, and `go7007_usb_probe` bails out to `allocfail` BEFORE any I2C adapter is added. So how could `i2c_add_adapter` even be called if the firmware request bombed out?
That makes me think maybe `request_firmware` *succeeded* in loading the necessary firmware. The syzkaller images might have `go7007/go7007fw.bin` already present, avoiding that failure. I need to confirm this.
However, maybe it's *not* a `go7007` issue. Let's look at the bug report. Okay, the allocation trace points to `kmalloc-4k`. The call chain is interesting: `kobject_uevent_env` -> `device_add` -> `device_create` -> `mon_bin_add`. Is `mon_bin_add` doing the allocation? No, that's almost certainly a red herring. It's just a random allocation reusing that memory. What's allocated is actually a `struct au0828_dev` or `struct go7007`, or something else that's 4096 bytes.
Now, wait... isn't `struct au0828_dev` allocated with `kzalloc(sizeof(*dev), GFP_KERNEL)`? I should check `sizeof(struct au0828_dev)`...
|
| 380/2 |
2026/07/30 13:19 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828.h FirstLine:200 LineCount:100]
Results: map[Contents: 200:
201: struct video_device vdev;
202: struct video_device vbi_dev;
203:
204: /* Videobuf2 */
205: struct vb2_queue vb_vidq;
206: struct vb2_queue vb_vbiq;
207: struct mutex vb_queue_lock;
208: struct mutex vb_vbi_queue_lock;
209:
210: unsigned int frame_count;
211: unsigned int vbi_frame_count;
212:
213: struct timer_list vid_timeout;
214: int vid_timeout_running;
215: struct timer_list vbi_timeout;
216: int vbi_timeout_running;
217:
218: int users;
219: int streaming_users;
220:
221: int width;
222: int height;
223: int vbi_width;
224: int vbi_height;
225: u32 vbi_read;
226: v4l2_std_id std;
227: u32 field_size;
228: u32 frame_size;
229: u32 bytesperline;
230: int type;
231: u8 ctrl_ainput;
232: __u8 isoc_in_endpointaddr;
233: u8 isoc_init_ok;
234: int greenscreen_detected;
235: int ctrl_freq;
236: int input_type;
237: int std_set_in_tuner_core;
238: unsigned int ctrl_input;
239: long unsigned int dev_state; /* defined at enum au0828_dev_state */;
240: enum au0828_stream_state stream_state;
241: wait_queue_head_t open;
242:
243: struct mutex lock;
244:
245: /* Isoc control struct */
246: struct au0828_dmaqueue vidq;
247: struct au0828_dmaqueue vbiq;
248: struct au0828_usb_isoc_ctl isoc_ctl;
249: spinlock_t slock;
250:
251: /* usb transfer */
252: int alt; /* alternate */
253: int max_pkt_size; /* max packet size of isoc transaction */
254: int num_alt; /* Number of alternative settings */
255: unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
256: struct urb *urb[AU0828_MAX_ISO_BUFS]; /* urb for isoc transfers */
257: char *transfer_buffer[AU0828_MAX_ISO_BUFS];/* transfer buffers for isoc
258: transfer */
259:
260: /* DVB USB / URB Related */
261: bool urb_streaming, need_urb_start;
262: struct urb *urbs[URB_COUNT];
263:
264: /* Preallocated transfer digital transfer buffers */
265:
266: char *dig_transfer_buffer[URB_COUNT];
267:
268: #ifdef CONFIG_MEDIA_CONTROLLER
269: struct media_device *media_dev;
270: struct media_pad video_pad, vbi_pad;
271: struct media_entity *decoder;
272: struct media_entity input_ent[AU0828_MAX_INPUT];
273: struct media_pad input_pad[AU0828_MAX_INPUT];
274: struct media_entity_notify entity_notify;
275: struct media_entity *tuner;
276: struct media_link *active_link;
277: struct media_entity *active_source;
278: struct media_entity *active_sink;
279: struct media_entity *active_link_owner;
280: struct media_entity *active_link_user;
281: struct media_pipeline *active_link_user_pipe;
282: bool active_link_shared;
283: #endif
284: };
285:
286:
287: /* ----------------------------------------------------------- */
288: #define au0828_read(dev, reg) au0828_readreg(dev, reg)
289: #define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value)
290: #define au0828_andor(dev, reg, mask, value) \
291: au0828_writereg(dev, reg, \
292: (au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask)))
293:
294: #define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit))
295: #define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0)
296:
297: /* ----------------------------------------------------------- */
298: /* au0828-core.c */
299: extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
]
|
| 381/2 |
2026/07/30 13:19 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 69438
output: 49
thoughts: 298
Thoughts: **Analyzing Potential Resource Leak in `au0828` Driver**
Okay, so I'm looking at this `au0828` driver code, and first thought that jumps out at me is, *man, `struct au0828_dev` is huge*! Not unexpected, but still, a large struct is always a potential area for complexity and, as we're seeing, potential errors. But, wait, I already think I found a bug right here in `au0828_usb_disconnect`!
Looking closer, the function `au0828_usb_disconnect` is pretty standard for a USB driver's disconnect handler. It retrieves the `au0828_dev` structure associated with the interface, and then attempts to unregister the analog device. The interesting part is this: If `au0828_analog_unregister(dev)` returns a non-zero value, it bails out early using a `return` statement. Now, I have to remember the behavior of `au0828_analog_unregister`, which is likely to return 1 when `dev->users > 0`, to indicate that the device is still in use.
But here's the kicker: in the case where `au0828_analog_unregister` returns 1, the `au0828_usb_release(dev)` function is *not* called! Aha! The return in that conditional leads to a resource leak and a potential double-free.
So I need to confirm whether it is possible for `au0828_analog_unregister` to return 1 under a circumstance where the driver hasn't already handled resource release or unmapping. Could this be from an error path in probe? Let's check `au0828_usb_probe` to see if it correctly handles errors.
|
| 382/2 |
2026/07/30 13:20 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:600 LineCount:50]
Results: map[Contents: 600: * by video or audio. Note that this step can't be done until dvb
601: * graph is created during dvb register.
602: */
603: media_device_for_each_entity(entity, dev->media_dev) {
604: switch (entity->function) {
605: case MEDIA_ENT_F_TUNER:
606: dev->tuner = entity;
607: break;
608: case MEDIA_ENT_F_ATV_DECODER:
609: dev->decoder = entity;
610: break;
611: case MEDIA_ENT_F_DTV_DEMOD:
612: demod = entity;
613: break;
614: }
615: }
616:
617: /* Disable link between tuner->demod and/or tuner->decoder */
618: if (dev->tuner) {
619: list_for_each_entry(link, &dev->tuner->links, list) {
620: if (demod && link->sink->entity == demod)
621: media_entity_setup_link(link, 0);
622: if (dev->decoder && link->sink->entity == dev->decoder)
623: media_entity_setup_link(link, 0);
624: }
625: }
626:
627: /* register entity_notify callback */
628: dev->entity_notify.notify_data = (void *) dev;
629: dev->entity_notify.notify = (void *) au0828_media_graph_notify;
630: media_device_register_entity_notify(dev->media_dev,
631: &dev->entity_notify);
632:
633: /* set enable_source */
634: mutex_lock(&dev->media_dev->graph_mutex);
635: dev->media_dev->source_priv = (void *) dev;
636: dev->media_dev->enable_source = au0828_enable_source;
637: dev->media_dev->disable_source = au0828_disable_source;
638: mutex_unlock(&dev->media_dev->graph_mutex);
639: #endif
640: return 0;
641: }
642:
643: static int au0828_usb_probe(struct usb_interface *interface,
644: const struct usb_device_id *id)
645: {
646: int ifnum;
647: int retval = 0;
648:
649: struct au0828_dev *dev;
]
|
| 383/2 |
2026/07/30 13:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 70983
output: 50
thoughts: 20
Thoughts: Okay, here's my take on those thoughts, framed from a first-person perspective, assuming I'm deep in the weeds of understanding `au0828_usb_probe`:
**Digging Deeper into `au0828_usb_probe`**
Right, I'm at a critical juncture. My initial assessment of `au0828_usb_probe` isn't enough; I can't just skim the surface. I realize I've hit a point where I absolutely *must* have the complete picture. The partial snippet I have isn't cutting it; I need the rest of the function definition to really understand its flow, its dependencies, and what critical initializations or checks are being performed. Without that, I'm flying blind, and this could lead to major misunderstandings. I need to get my hands on the full context. I'm going to track down the full source code and pore over it.
|
| 384/2 |
2026/07/30 13:20 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:650 LineCount:100]
Results: map[Contents: 650: struct usb_device *usbdev = interface_to_usbdev(interface);
651:
652: ifnum = interface->altsetting->desc.bInterfaceNumber;
653:
654: if (ifnum != 0)
655: return -ENODEV;
656:
657: dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
658: le16_to_cpu(usbdev->descriptor.idVendor),
659: le16_to_cpu(usbdev->descriptor.idProduct),
660: ifnum);
661:
662: /*
663: * Make sure we have 480 Mbps of bandwidth, otherwise things like
664: * video stream wouldn't likely work, since 12 Mbps is generally
665: * not enough even for most Digital TV streams.
666: */
667: if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
668: pr_err("au0828: Device initialization failed.\n");
669: pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
670: return -ENODEV;
671: }
672:
673: dev = kzalloc_obj(*dev);
674: if (dev == NULL) {
675: pr_err("%s() Unable to allocate memory\n", __func__);
676: return -ENOMEM;
677: }
678:
679: mutex_init(&dev->lock);
680: mutex_lock(&dev->lock);
681: mutex_init(&dev->mutex);
682: mutex_init(&dev->dvb.lock);
683: dev->usbdev = usbdev;
684: dev->boardnr = id->driver_info;
685: dev->board = au0828_boards[dev->boardnr];
686:
687: /* Initialize the media controller */
688: retval = au0828_media_device_init(dev, usbdev);
689: if (retval) {
690: pr_err("%s() au0828_media_device_init failed\n",
691: __func__);
692: mutex_unlock(&dev->lock);
693: kfree(dev);
694: return retval;
695: }
696:
697: retval = au0828_v4l2_device_register(interface, dev);
698: if (retval) {
699: au0828_usb_v4l2_media_release(dev);
700: mutex_unlock(&dev->lock);
701: kfree(dev);
702: return retval;
703: }
704:
705: /* Power Up the bridge */
706: au0828_write(dev, REG_600, 1 << 4);
707:
708: /* Bring up the GPIO's and supporting devices */
709: au0828_gpio_setup(dev);
710:
711: /* I2C */
712: au0828_i2c_register(dev);
713:
714: /* Setup */
715: au0828_card_setup(dev);
716:
717: /*
718: * Store the pointer to the au0828_dev so it can be accessed in
719: * au0828_usb_disconnect
720: */
721: usb_set_intfdata(interface, dev);
722:
723: /* Analog TV */
724: retval = au0828_analog_register(dev, interface);
725: if (retval) {
726: pr_err("%s() au0828_analog_register failed to register on V4L2\n",
727: __func__);
728: mutex_unlock(&dev->lock);
729: goto done;
730: }
731:
732: /* Digital TV */
733: retval = au0828_dvb_register(dev);
734: if (retval)
735: pr_err("%s() au0828_dvb_register failed\n",
736: __func__);
737:
738: /* Remote controller */
739: au0828_rc_register(dev);
740:
741: pr_info("Registered device AU0828 [%s]\n",
742: dev->board.name == NULL ? "Unset" : dev->board.name);
743:
744: mutex_unlock(&dev->lock);
745:
746: retval = au0828_media_device_register(dev, usbdev);
747:
748: done:
749: if (retval < 0)
]
|
| 385/2 |
2026/07/30 13:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 72772
output: 49
thoughts: 174
Thoughts: **Analyzing the au0828 Analog Registration Process**
Okay, so I'm looking at this code and immediately something jumps out at me: if `au0828_analog_register` fails, the execution jumps straight to `done`! That's... interesting. Why is it structured this way?
Let me follow the logic. Right after the `au0828_analog_register` call, we have a conditional check. If `retval` (the return value) indicates an error, an error message is printed and the mutex is unlocked. Makes sense, error handling. But then it *goes to* `done`.
And what happens at `done`? Aha! It calls `au0828_usb_disconnect` if the return value, `retval`, is negative. I need to understand that. So a failed registration results in attempting a disconnect. That's a key detail to note.
I'm getting a sense of the flow now. A failed analog registration triggers a cleanup sequence. It's a critical path. Now I've got to investigate `au0828_usb_disconnect` to figure out what kind of cleanup actions are performed and how they relate to the attempted analog registration.
|
| 386/2 |
2026/07/30 13:20 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:750 LineCount:50]
Results: map[Contents: 750: au0828_usb_disconnect(interface);
751:
752: return retval;
753: }
754:
755: static int au0828_suspend(struct usb_interface *interface,
756: pm_message_t message)
757: {
758: struct au0828_dev *dev = usb_get_intfdata(interface);
759:
760: if (!dev)
761: return 0;
762:
763: pr_info("Suspend\n");
764:
765: au0828_rc_suspend(dev);
766: au0828_v4l2_suspend(dev);
767: au0828_dvb_suspend(dev);
768:
769: /* FIXME: should suspend also ATV/DTV */
770:
771: return 0;
772: }
773:
774: static int au0828_resume(struct usb_interface *interface)
775: {
776: struct au0828_dev *dev = usb_get_intfdata(interface);
777: if (!dev)
778: return 0;
779:
780: pr_info("Resume\n");
781:
782: /* Power Up the bridge */
783: au0828_write(dev, REG_600, 1 << 4);
784:
785: /* Bring up the GPIO's and supporting devices */
786: au0828_gpio_setup(dev);
787:
788: au0828_rc_resume(dev);
789: au0828_v4l2_resume(dev);
790: au0828_dvb_resume(dev);
791:
792: /* FIXME: should resume also ATV/DTV */
793:
794: return 0;
795: }
796:
797: static struct usb_driver au0828_usb_driver = {
798: .name = KBUILD_MODNAME,
799: .probe = au0828_usb_probe,
]
|
| 387/2 |
2026/07/30 13:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 73959
output: 23
thoughts: 19
Thoughts: Here's my thought process, as if I were analyzing that code:
**Thinking Through the Disconnect Event**
Okay, so I'm digging through this log, looking at how the USB connection is handled. Hmm, `au0828_usb_disconnect`... I thought I'd seen that function earlier in the sequence. It's a bit jarring to see it referenced this late in the file, almost as if the disconnect process is an afterthought. I need to go back and double-check its initial declaration and usage within this context. I'm going to scan upward in the code; maybe I missed something significant the first time through. I need to understand the relationship between this disconnect function and the other USB-related calls β the timing is important. Is it getting called at the right point relative to the rest of the setup and data transfer? A disconnect being triggered too late could leave things in an undefined state. Gotta make sure it's cleaning up resources properly.
|
| 388/2 |
2026/07/30 13:20 |
tool |
grepper |
0m
Args: map[Expression:au0828_usb_disconnect]
Results: map[Output:drivers/media/usb/au0828/au0828-core.c=153=void au0828_usb_release(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-core.c-162-
drivers/media/usb/au0828/au0828-core.c:163:static void au0828_usb_disconnect(struct usb_interface *interface)
drivers/media/usb/au0828/au0828-core.c-164-{
--
drivers/media/usb/au0828/au0828-core.c=643=static int au0828_usb_probe(struct usb_interface *interface,
--
drivers/media/usb/au0828/au0828-core.c-718- * Store the pointer to the au0828_dev so it can be accessed in
drivers/media/usb/au0828/au0828-core.c:719: * au0828_usb_disconnect
drivers/media/usb/au0828/au0828-core.c-720- */
--
drivers/media/usb/au0828/au0828-core.c-749- if (retval < 0)
drivers/media/usb/au0828/au0828-core.c:750: au0828_usb_disconnect(interface);
drivers/media/usb/au0828/au0828-core.c-751-
--
drivers/media/usb/au0828/au0828-core.c=797=static struct usb_driver au0828_usb_driver = {
--
drivers/media/usb/au0828/au0828-core.c-799- .probe = au0828_usb_probe,
drivers/media/usb/au0828/au0828-core.c:800: .disconnect = au0828_usb_disconnect,
drivers/media/usb/au0828/au0828-core.c-801- .id_table = au0828_usb_id_table,
]
|
| 389/2 |
2026/07/30 13:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 74814
output: 49
thoughts: 15
Thoughts: Okay, here we go...
**Diving into au0828_usb_disconnect**
Alright, let's get down to brass tacks. The prompt says "Let's read `au0828_usb_disconnect`". So, my immediate thought is, "Okay, another delve into a USB disconnect function. Given my experience, I'm expecting this is going to be a crucial piece of the driver, the linchpin that gracefully handles the removal of a USB device associated with the au0828, which I know is a popular USB device often used for video capture. I'm already anticipating the nuances of resource management that I'll need to dissect β deallocating buffers, resetting hardware, and ensuring that no race conditions arise in the driver with other threads. "
"I need to understand this disconnect procedure completely. Was this written to handle hot-plug removal? How robust is this code? Is it a bare-bones implementation, or does it incorporate sophisticated error handling and state management? I need to look for typical USB disconnection steps: issuing an `usb_kill_urb`, cancelling pending transfers, releasing any claimed USB interfaces, and potentially resetting hardware components related to the au0828. I also want to make sure the right cleanup happens, like properly shutting down the video stream and releasing all the resources so the system isn't left in a bad state."
"I hope this code doesn't leave any dangling pointers, unreleased mutexes, or orphaned memory allocations. My goal is to ensure this disconnect routine is bulletproof and doesn't introduce any instability into the system. It would also be good to think about the situation where the user unplugs the USB cable while the device is in the middle of operation. I need to keep that kind of situation in mind."
|
| 390/2 |
2026/07/30 13:20 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:160 LineCount:50]
Results: map[Contents: 160: kfree(dev);
161: }
162:
163: static void au0828_usb_disconnect(struct usb_interface *interface)
164: {
165: struct au0828_dev *dev = usb_get_intfdata(interface);
166:
167: dprintk(1, "%s()\n", __func__);
168:
169: /* there is a small window after disconnect, before
170: dev->usbdev is NULL, for poll (e.g: IR) try to access
171: the device and fill the dmesg with error messages.
172: Set the status so poll routines can check and avoid
173: access after disconnect.
174: */
175: set_bit(DEV_DISCONNECTED, &dev->dev_state);
176:
177: au0828_rc_unregister(dev);
178: /* Digital TV */
179: au0828_dvb_unregister(dev);
180:
181: usb_set_intfdata(interface, NULL);
182: mutex_lock(&dev->mutex);
183: dev->usbdev = NULL;
184: mutex_unlock(&dev->mutex);
185: if (au0828_analog_unregister(dev)) {
186: /*
187: * No need to call au0828_usb_release() if V4L2 is enabled,
188: * as this is already called via au0828_usb_v4l2_release()
189: */
190: return;
191: }
192: au0828_usb_release(dev);
193: }
194:
195: static int au0828_media_device_init(struct au0828_dev *dev,
196: struct usb_device *udev)
197: {
198: #ifdef CONFIG_MEDIA_CONTROLLER
199: struct media_device *mdev;
200:
201: mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE);
202: if (IS_ERR(mdev))
203: return PTR_ERR(mdev);
204:
205: dev->media_dev = mdev;
206: #endif
207: return 0;
208: }
209:
]
|
| 391/2 |
2026/07/30 13:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 76003
output: 50
thoughts: 23
Thoughts: Here's my thought process, summarized as you requested:
**Deconstructing `au0828_analog_unregister`**
Okay, hold on a minute. I just saw that `au0828_analog_unregister` is returning an `int`. That's interesting. I need to understand what this return value signifies. Is it an error code? A success indicator? What are the possible values and what do they represent? I should immediately dive into the code and relevant documentation to verify how this function is intended to be used and what interpretations of the return value are. I'm going to track the function definition and implementation to understand potential error conditions or states.
|
| 392/2 |
2026/07/30 13:20 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-video.c FirstLine:1860 LineCount:50]
Results: map[Contents:1860: [AU0828_VMUX_COMPOSITE] = "Composite",
1861: [AU0828_VMUX_SVIDEO] = "S-Video",
1862: [AU0828_VMUX_CABLE] = "Cable TV",
1863: [AU0828_VMUX_TELEVISION] = "Television",
1864: [AU0828_VMUX_DVB] = "DVB",
1865: };
1866: int ret, i;
1867:
1868: /* Initialize Video and VBI pads */
1869: dev->video_pad.flags = MEDIA_PAD_FL_SINK;
1870: ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad);
1871: if (ret < 0)
1872: pr_err("failed to initialize video media entity!\n");
1873:
1874: dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
1875: ret = media_entity_pads_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad);
1876: if (ret < 0)
1877: pr_err("failed to initialize vbi media entity!\n");
1878:
1879: /* Create entities for each input connector */
1880: for (i = 0; i < AU0828_MAX_INPUT; i++) {
1881: struct media_entity *ent = &dev->input_ent[i];
1882:
1883: if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED)
1884: break;
1885:
1886: ent->name = inames[AUVI_INPUT(i).type];
1887: ent->flags = MEDIA_ENT_FL_CONNECTOR;
1888: dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
1889:
1890: switch (AUVI_INPUT(i).type) {
1891: case AU0828_VMUX_COMPOSITE:
1892: ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
1893: break;
1894: case AU0828_VMUX_SVIDEO:
1895: ent->function = MEDIA_ENT_F_CONN_SVIDEO;
1896: break;
1897: case AU0828_VMUX_CABLE:
1898: case AU0828_VMUX_TELEVISION:
1899: case AU0828_VMUX_DVB:
1900: default: /* Just to shut up a warning */
1901: ent->function = MEDIA_ENT_F_CONN_RF;
1902: break;
1903: }
1904:
1905: ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
1906: if (ret < 0)
1907: pr_err("failed to initialize input pad[%d]!\n", i);
1908:
1909: ret = media_device_register_entity(dev->media_dev, ent);
]
|
| 393/2 |
2026/07/30 13:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 77142
output: 23
thoughts: 17
Thoughts: Okay, let's see. My mind's buzzing β I've hit a snag. The key function I need right now is `au0828_analog_unregister`. This is what I'm focusing on; it's the one that's crucial to the next step. Where is this function defined? Need to track it down. Gotta remember its purpose and ensure it's handled the right way. This is essential to continue. Right, search... search...
|
| 394/2 |
2026/07/30 13:20 |
tool |
grepper |
0m
Args: map[Expression:au0828_analog_unregister]
Results: map[Output:drivers/media/usb/au0828/au0828-core.c=163=static void au0828_usb_disconnect(struct usb_interface *interface)
--
drivers/media/usb/au0828/au0828-core.c-184- mutex_unlock(&dev->mutex);
drivers/media/usb/au0828/au0828-core.c:185: if (au0828_analog_unregister(dev)) {
drivers/media/usb/au0828/au0828-core.c-186- /*
--
drivers/media/usb/au0828/au0828-video.c=911=static const struct vb2_ops au0828_video_qops = {
--
drivers/media/usb/au0828/au0828-video.c-923-/*
drivers/media/usb/au0828/au0828-video.c:924: * au0828_analog_unregister
drivers/media/usb/au0828/au0828-video.c-925- * unregister v4l2 devices
drivers/media/usb/au0828/au0828-video.c-926- */
drivers/media/usb/au0828/au0828-video.c:927:int au0828_analog_unregister(struct au0828_dev *dev)
drivers/media/usb/au0828/au0828-video.c-928-{
drivers/media/usb/au0828/au0828-video.c:929: dprintk(1, "au0828_analog_unregister called\n");
drivers/media/usb/au0828/au0828-video.c-930-
--
drivers/media/usb/au0828/au0828.h=327=extern int au0828_analog_register(struct au0828_dev *dev,
drivers/media/usb/au0828/au0828.h-328- struct usb_interface *interface);
drivers/media/usb/au0828/au0828.h:329:extern int au0828_analog_unregister(struct au0828_dev *dev);
drivers/media/usb/au0828/au0828.h-330-extern void au0828_usb_v4l2_media_release(struct au0828_dev *dev);
--
drivers/media/usb/au0828/au0828.h=337=static inline int au0828_analog_register(struct au0828_dev *dev,
--
drivers/media/usb/au0828/au0828.h-339-{ return 0; };
drivers/media/usb/au0828/au0828.h:340:static inline int au0828_analog_unregister(struct au0828_dev *dev)
drivers/media/usb/au0828/au0828.h-341-{ return 0; };
]
|
| 395/2 |
2026/07/30 13:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 78128
output: 49
thoughts: 15
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Analyzing the `au0828_analog_unregister` Function**
Alright, let's dive into the `au0828_analog_unregister` function. My initial thought process here is to quickly understand its role in the overall driver architecture for the AU0828 analog capture device. Since this is an unregister function, I'm expecting it to perform cleanup tasks related to device removal or driver unloading. I need to figure out the specific resources being managed and freed within this routine. I'll be looking for things like:
* **Resource De-allocation:** Are we releasing memory allocated for buffers, structures (e.g., control structures, DMA descriptors, I/O registers), or internal data? If so, what mechanisms are used (kfree, vfree, etc.)? Any potential memory leaks?
* **Hardware Control:** Are there any hardware-specific operations related to the analog capture chip that need to be reversed or disabled? Think about clock gating, power management (putting the chip into a low-power state or turning it off), and disabling any DMA channels used for capturing video/audio data. What are the register accesses and the side effects?
* **Driver State Management:** Does the function update any internal driver state variables (e.g., setting flags to indicate the device is no longer active, resetting counters, etc.)? This is critical for preventing further operations on a device that's being un-registered.
* **Interrupt Handling:** Are we disabling any associated interrupt handlers or cleaning up interrupt-related resources? Incorrect interrupt handling de-registration can lead to system instability or crashes.
* **Error Handling:** What kind of error checking is implemented, and how is it done? Do the checks include handling of potential errors that may result from incorrect sequencing during driver unregistration (e.g., the device being active during an unregister operation)?
* **Concurrency:** If the driver supports multiple instances or threads, are there any synchronization primitives (e.g., mutexes, spinlocks) used to protect shared resources during unregistration? Failure to handle concurrency correctly can cause race conditions and unpredictable behavior.
* **Device tree/platform data cleanup:** Is the device tree or platform data resources for this device correctly cleaned up?
I'll be paying close attention to any calls to other driver functions or kernel APIs, as these will likely provide further clues about the unregistration process. I'll scrutinize the call sequence to ensure that operations are performed in the correct order, avoiding potential deadlocks or resource conflicts. I'm also looking for any potential for resource leaks, errors in the unregistration procedure that could impact the stability of the system. I'll expect good use of `devm_xxx` functions for managed resources, but I'll double-check it.
|
| 396/2 |
2026/07/30 13:20 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-video.c FirstLine:920 LineCount:50]
Results: map[Contents: 920: /* ------------------------------------------------------------------
921: V4L2 interface
922: ------------------------------------------------------------------*/
923: /*
924: * au0828_analog_unregister
925: * unregister v4l2 devices
926: */
927: int au0828_analog_unregister(struct au0828_dev *dev)
928: {
929: dprintk(1, "au0828_analog_unregister called\n");
930:
931: /* No analog TV */
932: if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
933: return 0;
934:
935: mutex_lock(&au0828_sysfs_lock);
936: vb2_video_unregister_device(&dev->vdev);
937: vb2_video_unregister_device(&dev->vbi_dev);
938: mutex_unlock(&au0828_sysfs_lock);
939:
940: v4l2_device_disconnect(&dev->v4l2_dev);
941: v4l2_device_put(&dev->v4l2_dev);
942:
943: return 1;
944: }
945:
946: /* This function ensures that video frames continue to be delivered even if
947: the ITU-656 input isn't receiving any data (thereby preventing applications
948: such as tvtime from hanging) */
949: static void au0828_vid_buffer_timeout(struct timer_list *t)
950: {
951: struct au0828_dev *dev = timer_container_of(dev, t, vid_timeout);
952: struct au0828_dmaqueue *dma_q = &dev->vidq;
953: struct au0828_buffer *buf;
954: unsigned char *vid_data;
955: unsigned long flags = 0;
956:
957: spin_lock_irqsave(&dev->slock, flags);
958:
959: buf = dev->isoc_ctl.buf;
960: if (buf != NULL) {
961: vid_data = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
962: memset(vid_data, 0x00, buf->length); /* Blank green frame */
963: buffer_filled(dev, dma_q, buf);
964: }
965: get_next_buf(dma_q, &buf);
966:
967: if (dev->vid_timeout_running == 1)
968: mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
969:
]
|
| 397/2 |
2026/07/30 13:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 79650
output: 28
thoughts: 250
Thoughts: **Analyzing the Resource Cleanup in `au0828` Driver**
Okay, so I'm looking at this cleanup code for the `au0828` driver. My initial thought is that there's a potential issue with how resources are being released during disconnection. Specifically, I'm focusing on this `au0828_analog_unregister` function. Hang on, it returns `1` if the input type isn't undefined. Alright, and the logic here is that if `au0828_analog_unregister` returns `1`, then `au0828_usb_disconnect` exits early, skipping a call to `au0828_usb_release(dev)`.
The concern is, if we bail out early, we *don't* call `au0828_usb_release(dev)`. So, who's responsible for freeing those resources? The comment says that if V4L2 is enabled, the cleanup is handled by `au0828_usb_v4l2_release()`. So, the implication is that `au0828_usb_v4l2_release` is taking care of cleanup in that case. That's fine, but I need to make sure I understand the conditional logic completely. Let's go check the source for `au0828_usb_v4l2_release` to confirm that's the correct behavior.
|
| 398/2 |
2026/07/30 13:20 |
tool |
grepper |
0m
Args: map[Expression:au0828_usb_v4l2_release]
Results: map[Output:drivers/media/usb/au0828/au0828-core.c=163=static void au0828_usb_disconnect(struct usb_interface *interface)
--
drivers/media/usb/au0828/au0828-core.c-187- * No need to call au0828_usb_release() if V4L2 is enabled,
drivers/media/usb/au0828/au0828-core.c:188: * as this is already called via au0828_usb_v4l2_release()
drivers/media/usb/au0828/au0828-core.c-189- */
--
drivers/media/usb/au0828/au0828-video.c=622=void au0828_usb_v4l2_media_release(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-video.c-634-
drivers/media/usb/au0828/au0828-video.c:635:static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
drivers/media/usb/au0828/au0828-video.c-636-{
--
drivers/media/usb/au0828/au0828-video.c=646=int au0828_v4l2_device_register(struct usb_interface *interface,
--
drivers/media/usb/au0828/au0828-video.c-664-
drivers/media/usb/au0828/au0828-video.c:665: dev->v4l2_dev.release = au0828_usb_v4l2_release;
drivers/media/usb/au0828/au0828-video.c-666-
]
|
| 399/2 |
2026/07/30 13:20 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 80766
output: 49
thoughts: 126
Thoughts: **Analyzing the USB Video Device Release Sequence**
Okay, so I've got it. `au0828_usb_v4l2_release` is *definitely* the `release` callback associated with the `v4l2_dev` structure. That makes things a bit clearer. And looking at `au0828_analog_unregister`, I can see that it's calling `v4l2_device_put(&dev->v4l2_dev)`. This is key.
Now, if `v4l2_device_put` decrements the reference count and happens to drop the *last* reference to the `v4l2_dev` structure, then it's going to trigger that `au0828_usb_v4l2_release` function. That's the expected behavior, and it makes sense. It's the standard resource cleanup.
Time to confirm my understanding. I'm going to take a closer look at `au0828_usb_v4l2_release` itself and make absolutely sure everything checks out. Gotta verify it's doing what I *think* it's doing.
|
| 400/2 |
2026/07/30 13:21 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-video.c FirstLine:630 LineCount:50]
Results: map[Contents: 630: media_device_unregister_entity(&dev->input_ent[i]);
631: }
632: #endif
633: }
634:
635: static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
636: {
637: struct au0828_dev *dev =
638: container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
639:
640: v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
641: v4l2_device_unregister(&dev->v4l2_dev);
642: au0828_usb_v4l2_media_release(dev);
643: au0828_usb_release(dev);
644: }
645:
646: int au0828_v4l2_device_register(struct usb_interface *interface,
647: struct au0828_dev *dev)
648: {
649: int retval;
650:
651: if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
652: return 0;
653:
654: /* Create the v4l2_device */
655: #ifdef CONFIG_MEDIA_CONTROLLER
656: dev->v4l2_dev.mdev = dev->media_dev;
657: #endif
658: retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
659: if (retval) {
660: pr_err("%s() v4l2_device_register failed\n",
661: __func__);
662: return retval;
663: }
664:
665: dev->v4l2_dev.release = au0828_usb_v4l2_release;
666:
667: /* This control handler will inherit the controls from au8522 */
668: retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4);
669: if (retval) {
670: pr_err("%s() v4l2_ctrl_handler_init failed\n",
671: __func__);
672: return retval;
673: }
674: dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
675:
676: return 0;
677: }
678:
679: static int queue_setup(struct vb2_queue *vq,
]
|
| 401/2 |
2026/07/30 13:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 82030
output: 49
thoughts: 69
Thoughts: Here's my take on the situation:
**Investigating a Potential Double Free in the `au0828` Driver**
Okay, hold on a second. I'm looking at this `au0828_usb_v4l2_release` function, and it seems like it calls `au0828_usb_release(dev)`. That's the first red flag. And... damn, `au0828_usb_release(dev)` *frees* the `dev` structure. That's a huge potential problem. If `dev` gets freed multiple times, we're talking about a nasty double-free vulnerability, which is always a nightmare. This smells like a classic memory management bug. I need to make absolutely sure that this `dev` pointer isn't being used anywhere else *after* this call. Let's dig deeper into the code, and examine the `au0828_usb_release` function to be certain.
|
| 402/2 |
2026/07/30 13:21 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/au0828/au0828-core.c FirstLine:140 LineCount:50]
Results: map[Contents: 140:
141: /* clear enable_source, disable_source */
142: mutex_lock(&mdev->graph_mutex);
143: dev->media_dev->source_priv = NULL;
144: dev->media_dev->enable_source = NULL;
145: dev->media_dev->disable_source = NULL;
146: mutex_unlock(&mdev->graph_mutex);
147:
148: media_device_delete(dev->media_dev, KBUILD_MODNAME, THIS_MODULE);
149: dev->media_dev = NULL;
150: #endif
151: }
152:
153: void au0828_usb_release(struct au0828_dev *dev)
154: {
155: au0828_unregister_media_device(dev);
156:
157: /* I2C */
158: au0828_i2c_unregister(dev);
159:
160: kfree(dev);
161: }
162:
163: static void au0828_usb_disconnect(struct usb_interface *interface)
164: {
165: struct au0828_dev *dev = usb_get_intfdata(interface);
166:
167: dprintk(1, "%s()\n", __func__);
168:
169: /* there is a small window after disconnect, before
170: dev->usbdev is NULL, for poll (e.g: IR) try to access
171: the device and fill the dmesg with error messages.
172: Set the status so poll routines can check and avoid
173: access after disconnect.
174: */
175: set_bit(DEV_DISCONNECTED, &dev->dev_state);
176:
177: au0828_rc_unregister(dev);
178: /* Digital TV */
179: au0828_dvb_unregister(dev);
180:
181: usb_set_intfdata(interface, NULL);
182: mutex_lock(&dev->mutex);
183: dev->usbdev = NULL;
184: mutex_unlock(&dev->mutex);
185: if (au0828_analog_unregister(dev)) {
186: /*
187: * No need to call au0828_usb_release() if V4L2 is enabled,
188: * as this is already called via au0828_usb_v4l2_release()
189: */
]
|
| 403/2 |
2026/07/30 13:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 83140
output: 49
thoughts: 1582
Thoughts: **Analyzing the I2C Adapter Unregistration in `au0828` and `go7007` Drivers**
Okay, first things first, the `au0828` driver. I thought I had a problem there, but let's see. The `au0828_usb_release` function explicitly calls `au0828_i2c_unregister(dev)` *before* freeing the device structure. So, the I2C adapter is properly unregistered in `au0828`. This driver is *not* the source of my potential UAF. Now, I have to go back and check `go7007`.
Right, let's look again at the `go7007` driver. In `go7007_usb_release`, there's no call to `i2c_del_adapter`. That's a red flag. The `go7007_usb_probe` does register the I2C adapter with `i2c_add_adapter` if the board flags indicate it's using the EZ-USB I2C adapter. If the probe fails *after* this point, it jumps to `allocfail`. At `allocfail`, `go7007_usb_release` is called, and `go` is freed with `kfree(go)`. The I2C adapter *remains* registered. Bingo! That confirms it: this is definitely a Use-After-Free vulnerability.
But there's something else. How does the code reach `i2c_add_adapter` if the firmware loading fails? I need to check `go7007_boot_encoder` to see what causes it to return an error. The `go7007_boot_encoder` function calls `go7007_load_encoder`. Ah, `go7007_load_encoder` uses `request_firmware` to load `go7007/go7007fw.bin`. The vulnerability report could have included the firmware and the `request_firmware` could have succeeded, which would lead to I2C being registered! This is where syzkaller comes into the picture. Syzkaller images often include the `linux-firmware` package. So, it's very likely that `request_firmware` succeeds.
If `request_firmware` succeeds, then the code will continue. Specifically, the following lines:
```
if (go7007_interface_reset(go) < 0 ||
go7007_send_firmware(go, go->boot_fw, go->boot_fw_len) < 0 ||
go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
(intr_val & ~0x1) != 0x55aa) {
v4l2_err(go, "fatal error initializing GO7007\n");
return -1;
}
```
are executed.
If all those functions succeed, the `i2c_add_adapter` will be called. Specifically, `go7007_interface_reset` does a vendor request. This *must* succeed for the code to continue. So, if we provide a stub for the vendor request made by `go7007_interface_reset`, the `go7007_load_encoder` *will* succeed and `allocfail` will *not* be hit before `i2c_add_adapter`. If `allocfail` isn't hit before `i2c_add_adapter`, there is NO UAF. I now know what vendor requests are made in `go7007_load_encoder`.
|
| 404/2 |
2026/07/30 13:21 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:640 LineCount:50]
Results: map[Contents: 640:
641: static int go7007_usb_interface_reset(struct go7007 *go)
642: {
643: struct go7007_usb *usb = go->hpi_context;
644: u16 intr_val, intr_data;
645:
646: if (go->status == STATUS_SHUTDOWN)
647: return -1;
648: /* Reset encoder */
649: if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
650: return -1;
651: msleep(100);
652:
653: if (usb->board->flags & GO7007_USB_EZUSB) {
654: /* Reset buffer in EZ-USB */
655: pr_debug("resetting EZ-USB buffers\n");
656: if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 ||
657: go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0)
658: return -1;
659:
660: /* Reset encoder again */
661: if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
662: return -1;
663: msleep(100);
664: }
665:
666: /* Wait for an interrupt to indicate successful hardware reset */
667: if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
668: (intr_val & ~0x1) != 0x55aa) {
669: dev_err(go->dev, "unable to reset the USB interface\n");
670: return -1;
671: }
672: return 0;
673: }
674:
675: static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
676: int addr, int data)
677: {
678: struct go7007_usb *usb = go->hpi_context;
679: int i, r;
680: u16 status_reg = 0;
681: int timeout = 500;
682:
683: pr_debug("WriteInterrupt: %04x %04x\n", addr, data);
684:
685: for (i = 0; i < 100; ++i) {
686: r = usb_control_msg(usb->usbdev,
687: usb_rcvctrlpipe(usb->usbdev, 0), 0x14,
688: USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
689: 0, HPI_STATUS_ADDR, go->usb_buf,
]
|
| 405/2 |
2026/07/30 13:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 86529
output: 49
thoughts: 614
Thoughts: **Analyzing the go7007 USB Interrupt Write Process**
Okay, let's break this down. My initial observation is that `go7007_write_interrupt` calls `go7007_usb_ezusb_write_interrupt`. That's the core function we need to examine. Looking at `go7007_usb_ezusb_write_interrupt`, I see a clear sequence. First, it enters a loop, up to 100 iterations. Inside this loop, it issues a USB control message β a vendor request `0x14` β with direction IN, presumably to read a status register (`HPI_STATUS_ADDR` based on the context). It checks the retrieved `status_reg`. It seems like it's waiting for a specific bit (bit 4, `0x0010`) in `status_reg` to clear. There is a timeout of 10ms between checks, which is pretty standard for these sorts of loops. If the timeout is hit, or there is an error in reading the status register, it exits the loop. If we run through 100 iterations and *still* the bit hasn't cleared, it signals a device hung error.
Once that bit *is* clear, or it breaks out early from an error, it issues another USB control message, a vendor request `0x12`, this time an OUT transfer. This presumably writes the interrupt data. This is how the actual write occurs.
Following this function call, `go7007_usb_interface_reset` calls this function, sending two `0x10` requests.
The sequence then involves reading another interrupt. It looks like we're synchronizing by waiting for this bit in the status register to be clear before continuing, and then actually doing a write. This is a common pattern in USB devices to manage interrupt handshaking. I'd need to trace the status register and these vendor requests for a more precise understanding, but at this stage, it looks like it's a relatively straightforward write interrupt.
|
| 406/2 |
2026/07/30 13:21 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:720 LineCount:50]
Results: map[Contents: 720:
721: static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
722: int addr, int data)
723: {
724: struct go7007_usb *usb = go->hpi_context;
725: int r;
726: int timeout = 500;
727:
728: pr_debug("WriteInterrupt: %04x %04x\n", addr, data);
729:
730: go->usb_buf[0] = data & 0xff;
731: go->usb_buf[1] = data >> 8;
732: go->usb_buf[2] = addr & 0xff;
733: go->usb_buf[3] = addr >> 8;
734: go->usb_buf[4] = go->usb_buf[5] = go->usb_buf[6] = go->usb_buf[7] = 0;
735: r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00,
736: USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa,
737: 0xf0f0, go->usb_buf, 8, timeout);
738: if (r < 0) {
739: dev_err(go->dev, "error in WriteInterrupt: %d\n", r);
740: return r;
741: }
742: return 0;
743: }
744:
745: static void go7007_usb_readinterrupt_complete(struct urb *urb)
746: {
747: struct go7007 *go = (struct go7007 *)urb->context;
748: __le16 *regs = (__le16 *)urb->transfer_buffer;
749: int status = urb->status;
750:
751: if (status) {
752: if (status != -ESHUTDOWN &&
753: go->status != STATUS_SHUTDOWN) {
754: dev_err(go->dev, "error in read interrupt: %d\n", urb->status);
755: } else {
756: wake_up(&go->interrupt_waitq);
757: return;
758: }
759: } else if (urb->actual_length != urb->transfer_buffer_length) {
760: dev_err(go->dev, "short read in interrupt pipe!\n");
761: } else {
762: go->interrupt_available = 1;
763: go->interrupt_data = __le16_to_cpu(regs[0]);
764: go->interrupt_value = __le16_to_cpu(regs[1]);
765: pr_debug("ReadInterrupt: %04x %04x\n",
766: go->interrupt_value, go->interrupt_data);
767: }
768:
769: wake_up(&go->interrupt_waitq);
]
|
| 407/2 |
2026/07/30 13:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 88548
output: 50
thoughts: 422
Thoughts: **Analyzing the Interrupt Read and its Implications**
Okay, so I'm looking at this `go7007_read_interrupt` function, and the first thing that jumps out is that it's using a USB Request Block (URB) for the interrupt read. Specifically, it's submitting `usb->intr_urb`, which I see is linked to `ep_in[4]`. The function then waits for the URB to complete, using `wait_event_timeout`. If the interrupt doesn't arrive within 500ms (quite generous), it kills the URB and returns -1. No problem there. The code seems pretty straightforward, submitting the URB, waiting for the event and killing it if the event never comes.
Now, where this gets interesting is in relation to syzkaller's `syz_usb_connect`. If I recall correctly, it emulates URB responses through those `ep_in` arrays in `vusb_responses`. So, the failure scenarios for this `go7007_read_interrupt` might be interesting to craft.
Then, I'm thinking about the bigger picture. I want to cause this probe to fail, ideally after certain critical initializations have been done to trigger an interesting state. Let's see...If I can get `go7007_usb_probe` to fail after `i2c_add_adapter` has been called, that would be ideal! I remember, for the `PX_TV402U` device, the `i2c_add_adapter` call happens *before* `go7007_usb_vendor_request(go, 0x41, ...)`. So, I need to cause the probe to fail AFTER that.
Let's quickly refresh my memory by looking at the `go7007_usb_probe` function again...
|
| 408/2 |
2026/07/30 13:21 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/go7007/go7007-usb.c FirstLine:1160 LineCount:50]
Results: map[Contents:1160: /* Boot the GO7007 */
1161: if (go7007_boot_encoder(go, go->board_info->flags &
1162: GO7007_BOARD_USE_ONBOARD_I2C) < 0)
1163: goto allocfail;
1164:
1165: /* Register the EZ-USB I2C adapter, if we're using it */
1166: if (board->flags & GO7007_USB_EZUSB_I2C) {
1167: memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
1168: sizeof(go7007_usb_adap_templ));
1169: mutex_init(&usb->i2c_lock);
1170: go->i2c_adapter.dev.parent = go->dev;
1171: i2c_set_adapdata(&go->i2c_adapter, go);
1172: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
1173: dev_err(go->dev, "error: i2c_add_adapter failed\n");
1174: goto allocfail;
1175: }
1176: go->i2c_adapter_online = 1;
1177: }
1178:
1179: /* Pelco and Adlink reused the XMen and XMen-III vendor and product
1180: * IDs for their own incompatible designs. We can detect XMen boards
1181: * by probing the sensor, but there is no way to probe the sensors on
1182: * the Pelco and Adlink designs so we default to the Adlink. If it
1183: * is actually a Pelco, the user must set the assume_endura module
1184: * parameter. */
1185: if ((go->board_id == GO7007_BOARDID_XMEN ||
1186: go->board_id == GO7007_BOARDID_XMEN_III) &&
1187: go->i2c_adapter_online) {
1188: union i2c_smbus_data data;
1189:
1190: /* Check to see if register 0x0A is 0x76 */
1191: i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,
1192: I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);
1193: if (data.byte != 0x76) {
1194: if (assume_endura) {
1195: go->board_id = GO7007_BOARDID_ENDURA;
1196: usb->board = board = &board_endura;
1197: go->board_info = &board->main_info;
1198: strscpy(go->name, "Pelco Endura",
1199: sizeof(go->name));
1200: } else {
1201: u16 channel;
1202:
1203: /* read channel number from GPIO[1:0] */
1204: if (go7007_read_addr(go, 0x3c81, &channel))
1205: goto allocfail;
1206:
1207: channel &= 0x3;
1208: go->board_id = GO7007_BOARDID_ADLINK_MPG24;
1209: usb->board = board = &board_adlink_mpg24;
]
|
| 409/2 |
2026/07/30 13:21 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 90442
output: 36
thoughts: 979
Thoughts: **Debugging a Suspected UAF in I2C Adapter Lock**
Okay, let's break this down. My initial thought was that the `go7007` driver was the culprit, given the initial connection to the boot process and firmware loading. Specifically, I was thinking: `go7007_boot_encoder` *must* succeed for us to even reach `i2c_add_adapter`. And `go7007_boot_encoder` calls `go7007_load_encoder`, which in turn calls `request_firmware`. If `request_firmware` fails, then the whole `go7007_boot_encoder` sequence fails, right?
The code seems straightforward: if `go->boot_fw` is NULL, then `request_firmware` is called. A failure here returns -1, which is a clear signal. The thing is, this would be a common problem: syzkaller images don't come pre-loaded with `go7007fw.bin`. If `request_firmware` fails, then there's no way that `i2c_add_adapter` should have been called, but the bug report says it WAS called, meaning the failure is somewhere else.
This made me pause. How could this be possible? The bug report seems to contradict this, so I need to check the report again. The bug report is a slab-use-after-free in `i2c_adapter_lock_bus`. Okay, the UAF is in `i2c_adapter_lock_bus`. The allocation trace is critical. Here it is:
The allocation trace reveals the allocation is happening through `kobject_uevent_env`, ultimately used in `usb_register_bus` for `mon_bin_add`.
I see `env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL)`. My immediate thought was about the size. I was going to check the `sizeof(struct kobj_uevent_env)` value, since that would be key to understanding the allocation. From here, I need to check `kobject_uevent_env`, as it's the one allocating, using `kzalloc`.
The bug report says the buggy address belongs to an object in `kmalloc-4k`. But my intuition is that if `kobj_uevent_env` is the problem, that object will be 2048 bytes or less, so it should go into `kmalloc-2k`, right? That's what `sizeof(struct kobj_uevent_env)` should tell me. Why would a 2048-byte object land in `kmalloc-4k`? Is `kobj_uevent_env` actually larger than I think? Time to verify that size!
|
| 410/2 |
2026/07/30 13:22 |
tool |
read-file |
0m
Args: map[File:lib/kobject_uevent.c FirstLine:20 LineCount:50]
Results: map[Contents: 20: #include <linux/kmod.h>
21: #include <linux/slab.h>
22: #include <linux/socket.h>
23: #include <linux/skbuff.h>
24: #include <linux/netlink.h>
25: #include <linux/uidgid.h>
26: #include <linux/uuid.h>
27: #include <linux/ctype.h>
28: #include <net/sock.h>
29: #include <net/netlink.h>
30: #include <net/net_namespace.h>
31:
32:
33: atomic64_t uevent_seqnum;
34: #ifdef CONFIG_UEVENT_HELPER
35: char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
36: #endif
37:
38: struct uevent_sock {
39: struct list_head list;
40: struct sock *sk;
41: };
42:
43: #ifdef CONFIG_NET
44: static LIST_HEAD(uevent_sock_list);
45: /* This lock protects uevent_sock_list */
46: static DEFINE_MUTEX(uevent_sock_mutex);
47: #endif
48:
49: /* the strings here must match the enum in include/linux/kobject.h */
50: static const char *kobject_actions[] = {
51: [KOBJ_ADD] = "add",
52: [KOBJ_REMOVE] = "remove",
53: [KOBJ_CHANGE] = "change",
54: [KOBJ_MOVE] = "move",
55: [KOBJ_ONLINE] = "online",
56: [KOBJ_OFFLINE] = "offline",
57: [KOBJ_BIND] = "bind",
58: [KOBJ_UNBIND] = "unbind",
59: };
60:
61: static int kobject_action_type(const char *buf, size_t count,
62: enum kobject_action *type,
63: const char **args)
64: {
65: enum kobject_action action;
66: size_t count_first;
67: const char *args_start;
68: int ret = -EINVAL;
69:
]
|
| 411/2 |
2026/07/30 13:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 92790
output: 35
thoughts: 25
Thoughts: Here's my thought process, summarized as you requested:
**Navigating Kernel Object Structures**
Okay, so I'm digging into kernel object internals, specifically trying to understand the event environment. I need to know where this `struct kobj_uevent_env` is defined. Right, so my mental map suggests that anything related to kernel objects is probably going to be in `include/linux/kobject.h`. Let's confirm that. Yes, that makes sense. It's the logical place to start looking for definitions related to the fundamental building blocks of kernel objects and their event handling. That's a reasonable starting point.
|
| 412/2 |
2026/07/30 13:22 |
tool |
read-file |
0m
Args: map[File:include/linux/kobject.h FirstLine:20 LineCount:50]
Results: map[Contents: 20: #include <linux/sysfs.h>
21: #include <linux/compiler.h>
22: #include <linux/container_of.h>
23: #include <linux/spinlock.h>
24: #include <linux/kref.h>
25: #include <linux/kobject_ns.h>
26: #include <linux/wait.h>
27: #include <linux/atomic.h>
28: #include <linux/workqueue.h>
29: #include <linux/uidgid.h>
30:
31: #define UEVENT_HELPER_PATH_LEN 256
32: #define UEVENT_NUM_ENVP 64 /* number of env pointers */
33: #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */
34:
35: #ifdef CONFIG_UEVENT_HELPER
36: /* path to the userspace helper executed on an event */
37: extern char uevent_helper[];
38: #endif
39:
40: /* counter to tag the uevent, read only except for the kobject core */
41: extern atomic64_t uevent_seqnum;
42:
43: /*
44: * The actions here must match the index to the string array
45: * in lib/kobject_uevent.c
46: *
47: * Do not add new actions here without checking with the driver-core
48: * maintainers. Action strings are not meant to express subsystem
49: * or device specific properties. In most cases you want to send a
50: * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event
51: * specific variables added to the event environment.
52: */
53: enum kobject_action {
54: KOBJ_ADD,
55: KOBJ_REMOVE,
56: KOBJ_CHANGE,
57: KOBJ_MOVE,
58: KOBJ_ONLINE,
59: KOBJ_OFFLINE,
60: KOBJ_BIND,
61: KOBJ_UNBIND,
62: };
63:
64: struct kobject {
65: const char *name;
66: struct list_head entry;
67: struct kobject *parent;
68: struct kset *kset;
69: const struct kobj_type *ktype;
]
|
| 413/2 |
2026/07/30 13:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 93699
output: 36
thoughts: 17
Thoughts: Here's my thought process, as if I were considering that code:
**Navigating Kernel Data Structures**
Okay, I'm going through this code, and I see a reference to `struct kobj_uevent_env`. Hmm, I don't immediately recall the structure's contents or definition. No problem, that's not unusual when dealing with complex kernel code. I'll need to figure out what data is being passed around here. I notice the definition of `struct kobj_uevent_env` is further down in the file. I need to take note of that. I can continue reading, but I need to make sure I don't lose that reference. I'll probably want to jump back down to that definition to understand what's happening.
|
| 414/2 |
2026/07/30 13:22 |
tool |
read-file |
0m
Args: map[File:include/linux/kobject.h FirstLine:120 LineCount:50]
Results: map[Contents: 120: const struct kobj_ns_type_operations *(*child_ns_type)(const struct kobject *kobj);
121: const struct ns_common *(*namespace)(const struct kobject *kobj);
122: void (*get_ownership)(const struct kobject *kobj, kuid_t *uid, kgid_t *gid);
123: };
124:
125: struct kobj_uevent_env {
126: char *argv[3];
127: char *envp[UEVENT_NUM_ENVP];
128: int envp_idx;
129: char buf[UEVENT_BUFFER_SIZE];
130: int buflen;
131: };
132:
133: struct kset_uevent_ops {
134: int (* const filter)(const struct kobject *kobj);
135: const char *(* const name)(const struct kobject *kobj);
136: int (* const uevent)(const struct kobject *kobj, struct kobj_uevent_env *env);
137: };
138:
139: struct kobj_attribute {
140: struct attribute attr;
141: ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
142: char *buf);
143: ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
144: const char *buf, size_t count);
145: };
146:
147: extern const struct sysfs_ops kobj_sysfs_ops;
148:
149: struct sock;
150:
151: /**
152: * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
153: *
154: * A kset defines a group of kobjects. They can be individually
155: * different "types" but overall these kobjects all want to be grouped
156: * together and operated on in the same manner. ksets are used to
157: * define the attribute callbacks and other common events that happen to
158: * a kobject.
159: *
160: * @list: the list of all kobjects for this kset
161: * @list_lock: a lock for iterating over the kobjects
162: * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
163: * @uevent_ops: the set of uevent operations for this kset. These are
164: * called whenever a kobject has something happen to it so that the kset
165: * can add new environment variables, or filter out the uevents if so
166: * desired.
167: */
168: struct kset {
169: struct list_head list;
]
|
| 415/2 |
2026/07/30 13:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 94755
output: 23
thoughts: 245
Thoughts: **Analyzing a Kernel Memory Corruption Bug**
Okay, let me break this down. First, I need to understand the memory layout. The size of `struct kobj_uevent_env` is calculated as `3 * 8 + 64 * 8 + 4 + 2048 + 4 = 24 + 512 + 8 + 2048 = 2592` bytes. So, that means it's allocated from the `kmalloc-4k` cache. Got it. Now, the bug report... let's see. The buggy address is within an object at `ffff8880270b4000`, which *also* belongs to the `kmalloc-4k` cache. The important bit is that the report says the buggy address is 264 bytes *inside* a freed 4096-byte region, which is the exact size of one block from our `kmalloc-4k` pool. That's a classic heap out-of-bounds write after free!
The question is, what's being corrupted? The report doesn't explicitly state the object type, but let's assume it's `struct go7007` because of previous research. Now I need to figure out the location of something specific in that struct. If we were to assume the corruption originated there, where is `i2c_adapter` within `struct go7007`? I need to use `offsetof(struct go7007, i2c_adapter)` to find its position. That should help me figure out *what* exactly is being overwritten, or how it is related to other data structures in the process.
|
| 416/2 |
2026/07/30 13:22 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:dev OffsetBits:0 SizeBits:64] map[Name:bus_info OffsetBits:64 SizeBits:256] map[Name:board_info OffsetBits:320 SizeBits:64] map[Name:board_id OffsetBits:384 SizeBits:32] map[Name:tuner_type OffsetBits:416 SizeBits:32] map[Name:channel_number OffsetBits:448 SizeBits:32] map[Name:name OffsetBits:480 SizeBits:512] map[Name:vdev OffsetBits:1024 SizeBits:16064] map[Name:boot_fw OffsetBits:17088 SizeBits:64] map[Name:boot_fw_len OffsetBits:17152 SizeBits:32] map[Name:v4l2_dev OffsetBits:17216 SizeBits:1984] map[Name:hdl OffsetBits:19200 SizeBits:2432] map[Name:mpeg_video_encoding OffsetBits:21632 SizeBits:64] map[Name:mpeg_video_gop_size OffsetBits:21696 SizeBits:64] map[Name:mpeg_video_gop_closure OffsetBits:21760 SizeBits:64] map[Name:mpeg_video_bitrate OffsetBits:21824 SizeBits:64] map[Name:mpeg_video_aspect_ratio OffsetBits:21888 SizeBits:64] map[Name:mpeg_video_b_frames OffsetBits:21952 SizeBits:64] map[Name:mpeg_video_rep_seqheader OffsetBits:22016 SizeBits:64] map[Name:modet_mode OffsetBits:22080 SizeBits:64] map[Name:status OffsetBits:22144 SizeBits:32] map[Name:spinlock OffsetBits:22208 SizeBits:1024] map[Name:hw_lock OffsetBits:23232 SizeBits:1024] map[Name:serialize_lock OffsetBits:24256 SizeBits:1024] map[Name:audio_enabled OffsetBits:25280 SizeBits:32] map[Name:sd_video OffsetBits:25344 SizeBits:64] map[Name:sd_audio OffsetBits:25408 SizeBits:64] map[Name:usb_buf OffsetBits:25472 SizeBits:128] map[Name:input OffsetBits:25600 SizeBits:32] map[Name:aud_input OffsetBits:25632 SizeBits:32] map[Name:standard OffsetBits:25664 SizeBits:32] map[Name:std OffsetBits:25728 SizeBits:64] map[Name:sensor_framerate OffsetBits:25792 SizeBits:32] map[Name:width OffsetBits:25824 SizeBits:32] map[Name:height OffsetBits:25856 SizeBits:32] map[Name:encoder_h_offset OffsetBits:25888 SizeBits:32] map[Name:encoder_v_offset OffsetBits:25920 SizeBits:32] map[Name:encoder_h_halve OffsetBits:25952 SizeBits:1] map[Name:encoder_v_halve OffsetBits:25953 SizeBits:1] map[Name:encoder_subsample OffsetBits:25954 SizeBits:1] map[Name:format OffsetBits:25984 SizeBits:32] map[Name:bitrate OffsetBits:26016 SizeBits:32] map[Name:fps_scale OffsetBits:26048 SizeBits:32] map[Name:pali OffsetBits:26080 SizeBits:32] map[Name:aspect_ratio OffsetBits:26112 SizeBits:32] map[Name:gop_size OffsetBits:26144 SizeBits:32] map[Name:ipb OffsetBits:26176 SizeBits:1] map[Name:closed_gop OffsetBits:26177 SizeBits:1] map[Name:repeat_seqhead OffsetBits:26178 SizeBits:1] map[Name:seq_header_enable OffsetBits:26179 SizeBits:1] map[Name:gop_header_enable OffsetBits:26180 SizeBits:1] map[Name:dvd_mode OffsetBits:26181 SizeBits:1] map[Name:interlace_coding OffsetBits:26182 SizeBits:1] map[Name:modet_enable OffsetBits:26183 SizeBits:1] map[Name:modet OffsetBits:26208 SizeBits:512] map[Name:modet_map OffsetBits:26720 SizeBits:12992] map[Name:active_map OffsetBits:39712 SizeBits:1728] map[Name:modet_event_status OffsetBits:41440 SizeBits:32] map[Name:queue_lock OffsetBits:41472 SizeBits:1024] map[Name:vidq OffsetBits:42496 SizeBits:5568] map[Name:state OffsetBits:48064 SizeBits:32] map[Name:parse_length OffsetBits:48096 SizeBits:32] map[Name:modet_word OffsetBits:48128 SizeBits:16] map[Name:seen_frame OffsetBits:48160 SizeBits:32] map[Name:next_seq OffsetBits:48192 SizeBits:32] map[Name:vidq_active OffsetBits:48256 SizeBits:128] map[Name:frame_waitq OffsetBits:48384 SizeBits:1152] map[Name:active_buf OffsetBits:49536 SizeBits:64] map[Name:audio_deliver OffsetBits:49600 SizeBits:64] map[Name:snd_context OffsetBits:49664 SizeBits:64] map[Name:i2c_adapter_online OffsetBits:49728 SizeBits:32] map[Name:i2c_adapter OffsetBits:49792 SizeBits:17024] map[Name:hpi_ops OffsetBits:66816 SizeBits:64] map[Name:hpi_context OffsetBits:66880 SizeBits:64] map[Name:interrupt_available OffsetBits:66944 SizeBits:32] map[Name:interrupt_waitq OffsetBits:67008 SizeBits:1152] map[Name:interrupt_value OffsetBits:68160 SizeBits:16] map[Name:interrupt_data OffsetBits:68176 SizeBits:16]]]
|
| 417/2 |
2026/07/30 13:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 97252
output: 44
thoughts: 564
Thoughts: **Debugging a KASAN Slab-Use-After-Free in the I2C Subsystem**
Okay, let's break this down. The initial assumption that `i2c_adapter` might be at a particular offset (6224 bytes) within a larger object is quickly discarded. The buggy address reported (264 bytes into a 4096-byte region) eliminates `struct go7007` as the culprit, since that's much larger (8524 bytes) and would be allocated in a larger kmalloc slab. I see the bug report specifically mentions a `kmalloc-4k` region. This strongly suggests the object involved is *exactly* 4096 bytes.
The clue is the KASAN report pointing directly at `i2c_adapter_lock_bus`. I need to figure out which object, allocated in a 4k slab, contains an element at an offset of 264 bytes that is related to `i2c_adapter_lock_bus`. The buggy address `ffff8880270b4108` confirms this β the offset of 264 bytes is exact. This directly links to the `i2c_adapter_depth` function, which is ultimately calling `i2c_adapter_lock_bus`. Itβs likely that I need to investigate the structure and definition, and what is located at an offset of 264 bytes. Iβll need to check the definition of the `i2c_adapter` struct and its members, perhaps with `offsetof` to verify my suspicions.
|
| 418/2 |
2026/07/30 13:22 |
tool |
read-file |
0m
Args: map[File:drivers/i2c/i2c-core-base.c FirstLine:1230 LineCount:50]
Results: map[Contents:1230:
1231: static void i2c_adapter_dev_release(struct device *dev)
1232: {
1233: struct i2c_adapter *adap = to_i2c_adapter(dev);
1234: complete(&adap->dev_released);
1235: }
1236:
1237: unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
1238: {
1239: unsigned int depth = 0;
1240: struct device *parent;
1241:
1242: for (parent = adapter->dev.parent; parent; parent = parent->parent)
1243: if (parent->type == &i2c_adapter_type)
1244: depth++;
1245:
1246: WARN_ONCE(depth >= MAX_LOCKDEP_SUBCLASSES,
1247: "adapter depth exceeds lockdep subclass limit\n");
1248:
1249: return depth;
1250: }
1251: EXPORT_SYMBOL_GPL(i2c_adapter_depth);
1252:
1253: /*
1254: * Let users instantiate I2C devices through sysfs. This can be used when
1255: * platform initialization code doesn't contain the proper data for
1256: * whatever reason. Also useful for drivers that do device detection and
1257: * detection fails, either because the device uses an unexpected address,
1258: * or this is a compatible device with different ID register values.
1259: *
1260: * Parameter checking may look overzealous, but we really don't want
1261: * the user to provide incorrect parameters.
1262: */
1263: static ssize_t
1264: new_device_store(struct device *dev, struct device_attribute *attr,
1265: const char *buf, size_t count)
1266: {
1267: struct i2c_adapter *adap = to_i2c_adapter(dev);
1268: struct i2c_board_info info;
1269: struct i2c_client *client;
1270: char *blank, end;
1271: int res;
1272:
1273: memset(&info, 0, sizeof(struct i2c_board_info));
1274:
1275: blank = strchr(buf, ' ');
1276: if (!blank) {
1277: dev_err(dev, "%s: Missing parameters\n", "new_device");
1278: return -EINVAL;
1279: }
]
|
| 419/2 |
2026/07/30 13:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 98958
output: 19
thoughts: 70
Thoughts: **UAF Concerns with I2C Adapter Depth**
Okay, so I'm digging into this code and immediately see a potential problem. The `i2c_adapter_depth` function is accessing `parent->type`. I know that `parent` is ultimately derived from `adapter->dev.parent`. The alarm bells are going off because if `adapter->dev.parent` points to a memory location that's been freed, then that `parent->type` access is going to be a classic Use-After-Free (UAF) vulnerability. We *definitely* don't want that! Time to confirm my suspicion, let's look at the `offsetof(struct device, type)` to make sure I am correct, before I report this.
|
| 420/2 |
2026/07/30 13:22 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:kobj OffsetBits:0 SizeBits:512] map[Name:parent OffsetBits:512 SizeBits:64] map[Name:p OffsetBits:576 SizeBits:64] map[Name:init_name OffsetBits:640 SizeBits:64] map[Name:type OffsetBits:704 SizeBits:64] map[Name:bus OffsetBits:768 SizeBits:64] map[Name:driver OffsetBits:832 SizeBits:64] map[Name:platform_data OffsetBits:896 SizeBits:64] map[Name:driver_data OffsetBits:960 SizeBits:64] map[Name:driver_override OffsetBits:1024 SizeBits:1088] map[Name:mutex OffsetBits:2112 SizeBits:1024] map[Name:links OffsetBits:3136 SizeBits:448] map[Name:power OffsetBits:3584 SizeBits:5440] map[Name:pm_domain OffsetBits:9024 SizeBits:64] map[Name:msi OffsetBits:9088 SizeBits:128] map[Name:dma_mask OffsetBits:9216 SizeBits:64] map[Name:coherent_dma_mask OffsetBits:9280 SizeBits:64] map[Name:bus_dma_limit OffsetBits:9344 SizeBits:64] map[Name:dma_range_map OffsetBits:9408 SizeBits:64] map[Name:dma_parms OffsetBits:9472 SizeBits:64] map[Name:dma_pools OffsetBits:9536 SizeBits:128] map[Name:dma_mem OffsetBits:9664 SizeBits:64] map[Name:cma_area OffsetBits:9728 SizeBits:64] map[Name:dma_io_tlb_mem OffsetBits:9792 SizeBits:64] map[Name:archdata OffsetBits:9856 SizeBits:0] map[Name:of_node OffsetBits:9856 SizeBits:64] map[Name:fwnode OffsetBits:9920 SizeBits:64] map[Name:numa_node OffsetBits:9984 SizeBits:32] map[Name:devt OffsetBits:10016 SizeBits:32] map[Name:id OffsetBits:10048 SizeBits:32] map[Name:devres_lock OffsetBits:10112 SizeBits:1024] map[Name:devres_head OffsetBits:11136 SizeBits:128] map[Name:class OffsetBits:11264 SizeBits:64] map[Name:groups OffsetBits:11328 SizeBits:64] map[Name:release OffsetBits:11392 SizeBits:64] map[Name:iommu_group OffsetBits:11456 SizeBits:64] map[Name:iommu OffsetBits:11520 SizeBits:64] map[Name:physical_location OffsetBits:11584 SizeBits:64] map[Name:removable OffsetBits:11648 SizeBits:32] map[Name:flags OffsetBits:11712 SizeBits:64]]]
|
| 421/2 |
2026/07/30 13:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 100108
output: 23
thoughts: 459
Thoughts: **Analyzing a Potential Use-After-Free Vulnerability**
Okay, let's break this down. My initial observation was that the `type` field I was concerned about was at an offset of 88 bytes, or 704 bits, within a structure. However, the use-after-free (UAF) was happening at offset 264. That didn't make sense. I quickly realized 264 is 0x108. I double-checked the `offsetof` for `struct device.type` just to be sure, and the calculation of offsets seemed sound: `kobj` (64 bytes), `parent` (8 bytes), `p` (8 bytes), and `init_name` (8 bytes) added up correctly to 88.
The potential confusion here involves the `parent` pointer. If `parent` were a `struct usb_interface`, then a read of `parent->type` would indeed be at offset 88. But the UAF is happening at 264. So, this meant `parent` must not be a direct `struct usb_interface`.
I started digging deeper and found that the `parent` is actually accessed via `adapter->dev.parent`. Now it started to click. The relevant code in `go7007` sets `go->i2c_adapter.dev.parent = go->dev`. And `go->dev` is initialized as `&intf->dev`. This means it is the address of an embedded `struct device` within a `struct usb_interface`.
Here's the key: if `go->dev` is a pointer to `intf->dev`, then `intf->dev` is not directly freed. `intf` is freed when the USB device is disconnected. But if `go7007_usb_probe` fails early, the driver does not immediately free the `intf`.
So, the critical piece: if `go` gets freed, and `adapter` is embedded within `go`, then `adapter` is freed as well. This means a subsequent read from `adapter->dev.parent` is a use-after-free! I need to double-check `offsetof(struct i2c_adapter, dev.parent)` to confirm my understanding of the offsets. It looks like `adapter` is the crucial data structure here and it's being corrupted!
|
| 422/2 |
2026/07/30 13:22 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:owner OffsetBits:0 SizeBits:64] map[Name:class OffsetBits:64 SizeBits:32] map[Name:algo OffsetBits:128 SizeBits:64] map[Name:algo_data OffsetBits:192 SizeBits:64] map[Name:lock_ops OffsetBits:256 SizeBits:64] map[Name:bus_lock OffsetBits:320 SizeBits:1024] map[Name:mux_lock OffsetBits:1344 SizeBits:1024] map[Name:timeout OffsetBits:2368 SizeBits:32] map[Name:retries OffsetBits:2400 SizeBits:32] map[Name:dev OffsetBits:2432 SizeBits:11776] map[Name:locked_flags OffsetBits:14208 SizeBits:64] map[Name:nr OffsetBits:14272 SizeBits:32] map[Name:name OffsetBits:14304 SizeBits:384] map[Name:dev_released OffsetBits:14720 SizeBits:704] map[Name:userspace_clients_lock OffsetBits:15424 SizeBits:1024] map[Name:userspace_clients OffsetBits:16448 SizeBits:128] map[Name:bus_recovery_info OffsetBits:16576 SizeBits:64] map[Name:quirks OffsetBits:16640 SizeBits:64] map[Name:host_notify_domain OffsetBits:16704 SizeBits:64] map[Name:bus_regulator OffsetBits:16768 SizeBits:64] map[Name:debugfs OffsetBits:16832 SizeBits:64] map[Name:addrs_in_instantiation OffsetBits:16896 SizeBits:128]]]
|
| 423/2 |
2026/07/30 13:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 101613
output: 43
thoughts: 407
Thoughts: **Analyzing a Potential Use-After-Free Vulnerability**
Okay, first things first, I need to get my bearings. The reported bug indicates a Use-After-Free (UAF) within the `i2c_adapter` structure. My initial thought is to trace the memory layout to see how things are arranged. Let's start with the provided offsets, and see where they land in memory. So, `dev` is at offset 2432 bits, which is 304 bytes into the `i2c_adapter` struct, and `dev.parent` is 64 bytes further. Interesting, but not immediately relevant.
The UAF is reported at offset 264. I'll need to confirm that. 264 in decimal? That's `0x108` in hex. Now, let's see what data is at that offset of the `struct i2c_adapter`. To get there I need `264 * 8 = 2112` bits. Okay, I'm thinking I've identified something.
Let's see what's nearby. `bus_lock` is at offset 320 bits, or 40 bytes. And it's a `struct rt_mutex`, which I know is 1024 bits, or 128 bytes, in size. That means `bus_lock` ends at 168 bytes. Now, `mux_lock` starts at 1344 bits, so 168 bytes! It's another `struct rt_mutex`, so 128 bytes. So `mux_lock` ends at 296 bytes.
Now I see it! Offset 264 is *inside* `mux_lock`! That's a significant detail and likely where the vulnerability lies.
Let's double-check the bug report to confirm the location. `i2c_adapter_depth` and `i2c_adapter_lock_bus`. I'll want to check the code for `i2c_adapter_lock_bus` to get the context here. Now, I have to look deeper to see what's happening at those addresses.
|
| 424/2 |
2026/07/30 13:22 |
tool |
read-file |
0m
Args: map[File:drivers/i2c/i2c-core-base.c FirstLine:840 LineCount:50]
Results: map[Contents: 840: /**
841: * i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
842: * @adapter: Target I2C bus segment
843: * @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT
844: * locks only this branch in the adapter tree
845: */
846: static void i2c_adapter_lock_bus(struct i2c_adapter *adapter,
847: unsigned int flags)
848: {
849: rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter));
850: }
851:
852: /**
853: * i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment
854: * @adapter: Target I2C bus segment
855: * @flags: I2C_LOCK_ROOT_ADAPTER trylocks the root i2c adapter, I2C_LOCK_SEGMENT
856: * trylocks only this branch in the adapter tree
857: */
858: static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter,
859: unsigned int flags)
860: {
861: return rt_mutex_trylock(&adapter->bus_lock);
862: }
863:
864: /**
865: * i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment
866: * @adapter: Target I2C bus segment
867: * @flags: I2C_LOCK_ROOT_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT
868: * unlocks only this branch in the adapter tree
869: */
870: static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter,
871: unsigned int flags)
872: {
873: rt_mutex_unlock(&adapter->bus_lock);
874: }
875:
876: static void i2c_dev_set_name(struct i2c_adapter *adap,
877: struct i2c_client *client,
878: struct i2c_board_info const *info)
879: {
880: struct acpi_device *adev = ACPI_COMPANION(&client->dev);
881:
882: if (info && info->dev_name) {
883: dev_set_name(&client->dev, "i2c-%s", info->dev_name);
884: return;
885: }
886:
887: if (adev) {
888: dev_set_name(&client->dev, "i2c-%s", acpi_dev_name(adev));
889: return;
]
|
| 425/2 |
2026/07/30 13:22 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 103402
output: 25
thoughts: 691
Thoughts: **Debugging a Use-After-Free Vulnerability in I2C Adapter Locking**
Okay, so I'm looking at this KASAN report, a slab-use-after-free in `i2c_adapter_lock_bus`. The function calls `rt_mutex_lock_nested` with the `adapter->bus_lock` and the result of `i2c_adapter_depth(adapter)`. The first thing that jumps out is that `i2c_adapter_depth` is evaluated *before* the lock is attempted. I'm already spotting a potential race here, but need to follow the data.
My immediate thought is to check `i2c_adapter_depth` again to see what is going on. I can see that this function accesses `adapter->dev.parent`. Now, the initial bug report references an offset of 264 for the use-after-free, while `adapter->dev.parent` is actually at offset 368 in the `i2c_adapter` struct. That doesn't make sense. And, `i2c_adapter_depth` is inlined, so that's another thing I'll need to keep in mind.
I'm thinking, could `adapter` actually be a pointer to something *other* than an `i2c_adapter`? The function signature takes a `struct i2c_adapter *`, so this is key. But what if the `i2c_adapter` structure is embedded within a *different* structure? Yeah, that's it! What if `adapter` is a pointer to the *containing* struct, like `go7007` or something similar?
I look at the `struct go7007`, and yes, there is an `i2c_adapter` embedded within it, called `go->i2c_adapter`. I go to check the offset of `i2c_adapter` within `struct go7007`. Wait... it's a huge offset - 6224 bytes! That object is 8524 bytes in total. That also means that this struct can't be allocated from `kmalloc-4k`. The freed object size is 4096 bytes, but that isn't the struct we are looking at. So, that's not it.
Okay, let's step back. What other object is 4096 bytes and contains an `i2c_adapter`? Hmm, let's check `au0828_dev`. Time to check `offsetof(struct au0828_dev, i2c_adap)`... let's see where that takes me. This looks promising.
|
| 426/2 |
2026/07/30 13:23 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:mutex OffsetBits:0 SizeBits:1024] map[Name:usbdev OffsetBits:1024 SizeBits:64] map[Name:boardnr OffsetBits:1088 SizeBits:32] map[Name:board OffsetBits:1152 SizeBits:896] map[Name:ctrlmsg OffsetBits:2048 SizeBits:512] map[Name:i2c_adap OffsetBits:2560 SizeBits:17024] map[Name:i2c_algo OffsetBits:19584 SizeBits:448] map[Name:i2c_client OffsetBits:20032 SizeBits:12416] map[Name:i2c_rc OffsetBits:32448 SizeBits:32] map[Name:dvb OffsetBits:32512 SizeBits:24512] map[Name:restart_streaming OffsetBits:57024 SizeBits:576] map[Name:bulk_timeout OffsetBits:57600 SizeBits:640] map[Name:bulk_timeout_running OffsetBits:58240 SizeBits:32] map[Name:v4l2_dev OffsetBits:58304 SizeBits:1984] map[Name:v4l2_ctrl_hdl OffsetBits:60288 SizeBits:2432] map[Name:ir OffsetBits:62720 SizeBits:64] map[Name:vdev OffsetBits:62784 SizeBits:16064] map[Name:vbi_dev OffsetBits:78848 SizeBits:16064] map[Name:vb_vidq OffsetBits:94912 SizeBits:5568] map[Name:vb_vbiq OffsetBits:100480 SizeBits:5568] map[Name:vb_queue_lock OffsetBits:106048 SizeBits:1024] map[Name:vb_vbi_queue_lock OffsetBits:107072 SizeBits:1024] map[Name:frame_count OffsetBits:108096 SizeBits:32] map[Name:vbi_frame_count OffsetBits:108128 SizeBits:32] map[Name:vid_timeout OffsetBits:108160 SizeBits:640] map[Name:vid_timeout_running OffsetBits:108800 SizeBits:32] map[Name:vbi_timeout OffsetBits:108864 SizeBits:640] map[Name:vbi_timeout_running OffsetBits:109504 SizeBits:32] map[Name:users OffsetBits:109536 SizeBits:32] map[Name:streaming_users OffsetBits:109568 SizeBits:32] map[Name:width OffsetBits:109600 SizeBits:32] map[Name:height OffsetBits:109632 SizeBits:32] map[Name:vbi_width OffsetBits:109664 SizeBits:32] map[Name:vbi_height OffsetBits:109696 SizeBits:32] map[Name:vbi_read OffsetBits:109728 SizeBits:32] map[Name:std OffsetBits:109760 SizeBits:64] map[Name:field_size OffsetBits:109824 SizeBits:32] map[Name:frame_size OffsetBits:109856 SizeBits:32] map[Name:bytesperline OffsetBits:109888 SizeBits:32] map[Name:type OffsetBits:109920 SizeBits:32] map[Name:ctrl_ainput OffsetBits:109952 SizeBits:8] map[Name:isoc_in_endpointaddr OffsetBits:109960 SizeBits:8] map[Name:isoc_init_ok OffsetBits:109968 SizeBits:8] map[Name:greenscreen_detected OffsetBits:109984 SizeBits:32] map[Name:ctrl_freq OffsetBits:110016 SizeBits:32] map[Name:input_type OffsetBits:110048 SizeBits:32] map[Name:std_set_in_tuner_core OffsetBits:110080 SizeBits:32] map[Name:ctrl_input OffsetBits:110112 SizeBits:32] map[Name:dev_state OffsetBits:110144 SizeBits:64] map[Name:stream_state OffsetBits:110208 SizeBits:32] map[Name:open OffsetBits:110272 SizeBits:1152] map[Name:lock OffsetBits:111424 SizeBits:1024] map[Name:vidq OffsetBits:112448 SizeBits:192] map[Name:vbiq OffsetBits:112640 SizeBits:192] map[Name:isoc_ctl OffsetBits:112832 SizeBits:704] map[Name:slock OffsetBits:113536 SizeBits:1024] map[Name:alt OffsetBits:114560 SizeBits:32] map[Name:max_pkt_size OffsetBits:114592 SizeBits:32] map[Name:num_alt OffsetBits:114624 SizeBits:32] map[Name:alt_max_pkt_size OffsetBits:114688 SizeBits:64] map[Name:urb OffsetBits:114752 SizeBits:768] map[Name:transfer_buffer OffsetBits:115520 SizeBits:768] map[Name:urb_streaming OffsetBits:116288 SizeBits:8] map[Name:need_urb_start OffsetBits:116296 SizeBits:8] map[Name:urbs OffsetBits:116352 SizeBits:1024] map[Name:dig_transfer_buffer OffsetBits:117376 SizeBits:1024] map[Name:media_dev OffsetBits:118400 SizeBits:64] map[Name:video_pad OffsetBits:118464 SizeBits:512] map[Name:vbi_pad OffsetBits:118976 SizeBits:512] map[Name:decoder OffsetBits:119488 SizeBits:64] map[Name:input_ent OffsetBits:119552 SizeBits:3840] map[Name:input_pad OffsetBits:123392 SizeBits:2048] map[Name:entity_notify OffsetBits:125440 SizeBits:256] map[Name:tuner OffsetBits:125696 SizeBits:64] map[Name:active_link OffsetBits:125760 SizeBits:64] map[Name:active_source OffsetBits:125824 SizeBits:64] map[Name:active_sink OffsetBits:125888 SizeBits:64] map[Name:active_link_owner OffsetBits:125952 SizeBits:64] map[Name:active_link_user OffsetBits:126016 SizeBits:64] map[Name:active_link_user_pipe OffsetBits:126080 SizeBits:64] map[Name:active_link_shared OffsetBits:126144 SizeBits:8]]]
|
| 427/2 |
2026/07/30 13:23 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 106728
output: 21
thoughts: 902
Thoughts: **Analyzing a Potential Use-After-Free Vulnerability**
Okay, first things first. The size of `struct au0828_dev` is huge, way bigger than the 4096 bytes being discussed. It's definitely not allocated from a 4k kmalloc cache. So, what *is* allocated in 4096-byte chunks? I remember the bug report mentioning the address `ffff8880270b4000` belonging to a `kmalloc-4k` cache and the problematic offset being 264 bytes into the freed region. The actual buggy address is `ffff8880270b4108`, which confirms the offset.
Now, what object is exactly 4096 bytes? Is it a driver-specific object? My gut says to check the `i2c_adapter` structure. Let's see... `sizeof(struct i2c_adapter)` comes out to 2128 bytes, which, yes, would be allocated from a `kmalloc-4k` region since it's larger than `kmalloc-2k` which is 2048 bytes. Okay, the `i2c_adapter` struct is allocated from `kmalloc-4k`! It can be embedded in things like `go7007` and `au0828_dev`, but what if the driver allocates it dynamically?
So, if `struct i2c_adapter` is allocated from `kmalloc-4k`, then the potential use-after-free (UAF) could be at offset 264 within that structure. Let's check the offsets. The bug refers to the `bus_lock` member of the `i2c_adapter`. Alright, `offsetof(struct i2c_adapter, bus_lock)` is 40 bytes. That's a `rt_mutex`. And an `rt_mutex` is 128 bytes. The memory map of `bus_lock` would then be from offset 40 bytes to 168.
So, what's at offset 264? Let's check `offsetof(struct i2c_adapter, dev.parent)`. The `dev` member starts at offset 304, and `dev.parent` is actually 64 bytes into that, starting at offset 368.
However, the question remains: what's at offset 264? I'm missing something here. Let's look at the `i2c_adapter_lock_bus` function itself. It's using the `bus_lock`, so it's a `rt_mutex_lock_nested`.
The `rt_mutex` has a `wait_lock` (4 bytes), `waiters` (16 bytes), and an `owner` (8 bytes) so it's *not* 128 bytes in size! I need to check the real size of `struct rt_mutex` to be certain.
|
| 428/2 |
2026/07/30 13:23 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:rtmutex OffsetBits:0 SizeBits:704] map[Name:dep_map OffsetBits:704 SizeBits:320]]]
|
| 429/2 |
2026/07/30 13:23 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 108364
output: 25
thoughts: 2165
Thoughts: **Analyzing a KASAN Slab-Use-After-Free Bug**
Okay, so I'm diving into this KASAN report, and my initial thought was that it was an `i2c_adapter` issue. The report points to a slab-use-after-free within `i2c_adapter_lock_bus`. I started by trying to map the structure offsets, thinking I might be able to pinpoint where the erroneous access occurs. I quickly realized `rt_mutex` is 128 bytes (1024 bits), `bus_lock` runs from offset 40-168 and `mux_lock` starts at offset 1344 bits or 168 bytes. I checked the offset 264 and confirmed it falls inside `mux_lock`. But then I realized `i2c_adapter_lock_bus` isn't touching `mux_lock`, which made me pause.
The bug report mentions access to `adapter->dev.parent`. If `dev.parent` is at offset 264, then `dev` itself would be at offset 200, which seemed odd. I wanted to verify this with `offsetof(struct i2c_adapter, dev)`. Previously, in a related query, it was at 304 bytes. Then I remembered that `CONFIG_LOCKDEP` can alter the size of `rt_mutex`, adding `dep_map`. Syzkaller kernels usually have it enabled. I should check the size of `struct i2c_adapter` in the actual kernel configuration.
I started to break down the structure, manually calculating offsets: `owner` (8 bytes), `class` (4), padding (4), `algo` (8), `algo_data` (8), `lock_ops` (8). These totaled 40 bytes before the `bus_lock`. Assuming 32 bytes for `rt_mutex` (without `dep_map`), and another 32 for `mux_lock`, `timeout` (4), `retries` (4), then `dev` might be at offset 104+8=112 bytes and `dev.parent` at 176 bytes which is NOT 264. I even considered if there's padding or a bigger `rt_mutex`. I re-checked, but even with 72 bytes for the `rt_mutex` the offset would not be 264 bytes. If `dev.parent` *is* at 264, `dev` would be at 200, but I don't know why it would be there.
Then, a sudden thought: what if the accessed memory isn't actually an `i2c_adapter`? I checked the allocation trace: it goes through `kmalloc_reserve`, `__alloc_skb`, and so on. Wait a second, this is `sk_buff` data allocation! The size is 4096 bytes. The free trace also confirms this: `skb_kfree_head`, `skb_release_data`, etc. That changes everything!
This is an `sk_buff` buffer! The UAF is happening on a memory region that was used for `sk_buff` data and was *reallocated*. KASAN reports the *last* allocation/free, so the issue must be with the re-use. However, if the memory was reallocated, KASAN would report the *new* allocation, which it does not.
So, the object was allocated, freed, and *then* accessed. An `sk_buff` object was freed, then accessed as an `i2c_adapter`. This means the `i2c_adapter` itself was allocated first, then freed, then the memory was re-allocated as `sk_buff` data, then freed again, and then accessed as `i2c_adapter`.
I'm starting to zero in on a pattern now. The allocation would have to be through `kmalloc-4k`, which makes sense because this is an `sk_buff` buffer. I was previously considering objects that are in the 8k or 16k slabs. Now I need to identify which `kmalloc-4k` object might contain the `i2c_adapter`.
|
| 430/2 |
2026/07/30 13:23 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:sd OffsetBits:0 SizeBits:3072] map[Name:ctrl_handler OffsetBits:3072 SizeBits:2432] map[Name: OffsetBits:5504 SizeBits:1856] map[Name:work OffsetBits:7360 SizeBits:704] map[Name:vdd OffsetBits:8064 SizeBits:64] map[Name:vio OffsetBits:8128 SizeBits:64] map[Name:gpio_reset OffsetBits:8192 SizeBits:64] map[Name:pd OffsetBits:8256 SizeBits:64] map[Name:power_state OffsetBits:8320 SizeBits:32] map[Name:rds_enabled OffsetBits:8352 SizeBits:32] map[Name:frequency OffsetBits:8384 SizeBits:32] map[Name:preemphasis OffsetBits:8416 SizeBits:32] map[Name:stereo OffsetBits:8448 SizeBits:32] map[Name:tune_rnl OffsetBits:8480 SizeBits:32]]]
|
| 431/2 |
2026/07/30 13:23 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 111788
output: 25
thoughts: 206
Thoughts: **Analyzing I2C Adapter Memory Allocation**
Okay, so I'm digging into this memory allocation stuff. The `si4713_device`, that's 1060 bytes, right? Yeah, that's definitely landing in either `kmalloc-1k` or `kmalloc-2k`. But wait, what about the `i2c_adapter` struct itself? That's the real key here.
If it's dynamically allocated, which is pretty common, it's usually done with something like `kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL)`. Okay, let me quickly double-check the size... Hold on... 2128 bytes with lockdep! Right. That pushes it into `kmalloc-4k`. Not what I initially expected.
So now, the real question is, which drivers are allocating `i2c_adapter` dynamically and are they potentially leaking it or, even worse, using it after it's been freed (UAF)? Time to track down potential issues! I need to search through the code for those dynamic allocations. Let's see... I'll search for `kzalloc(sizeof(struct i2c_adapter)` or `kzalloc(sizeof(*adapter)`. That should do the trick. Usually, it's embedded in another structure, but I know it's sometimes allocated directly.
|
| 432/2 |
2026/07/30 13:23 |
tool |
grepper |
0m
Error:
Args: map[Expression:kzalloc\(sizeof\(struct i2c_adapter]
Results:
|
| 433/2 |
2026/07/30 13:23 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 112331
output: 22
thoughts: 22
Thoughts: Here's my thought process, as if I were considering this search:
**Diving into Kernel Memory Allocation**
Okay, so I need to track down specific instances of kernel memory allocation. My mind immediately goes to `kzalloc`, a key function for zero-initialized allocation. Given that, I want to find where we're allocating memory for some data structure, probably a driver adapter. The `sizeof(*adap` and `sizeof(*adapter` variations should catch most occurrences where we're calculating memory needs. The `*` indicates a pointer dereference, which is the crucial bit. By using `sizeof` with a dereferenced pointer, we calculate the size required for the *structure* pointed to by the adapter pointer. This approach is much safer than just hardcoding a size. This will help me locate all calls to `kzalloc` related to a specific struct type. That seems like a solid search strategy.
|
| 434/2 |
2026/07/30 13:23 |
tool |
grepper |
0m
Args: map[Expression:kzalloc\(sizeof\(\*adap]
Results: map[Output:drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c=6571=static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
--
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c-6636- adapter->msg_enable = DFLT_MSG_ENABLE;
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c:6637: adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) +
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c-6638- (sizeof(struct mbox_cmd) *
--
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c=2895=static int cxgb4vf_pci_probe(struct pci_dev *pdev,
--
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c-2946-
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c:2947: adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) +
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c-2948- (sizeof(struct mbox_cmd) *
]
|
| 435/2 |
2026/07/30 13:23 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 112948
output: 24
thoughts: 35
Thoughts: **Navigating the Driver Landscape**
Okay, hold on a second. I was initially thinking `cxgb4` was related to I2C, but that doesn't seem right. That was a hasty assumption. I need to be more precise in my search. My intuition is telling me that the relevant code will be using something like `kzalloc` which is a good indicator of memory allocation within a kernel driver. So, instead of looking at the initial assumption, I need to focus my search on the I2C bus drivers. Let's start with a focused search within the `drivers/i2c/busses/` directory and see where that leads. That should give me the I2C bus driver and I will then be able to assess the code associated with memory allocation for the driver.
|
| 436/2 |
2026/07/30 13:23 |
tool |
grepper |
0m
Args: map[Expression:kzalloc.*sizeof.*i2c_adapter]
Results: map[Output:drivers/i2c/busses/i2c-cbus-gpio.c=210=static int cbus_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-cbus-gpio.c-214-
drivers/i2c/busses/i2c-cbus-gpio.c:215: adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter),
drivers/i2c/busses/i2c-cbus-gpio.c-216- GFP_KERNEL);
--
drivers/i2c/busses/i2c-cp2615.c=282=cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id)
--
drivers/i2c/busses/i2c-cp2615.c-295-
drivers/i2c/busses/i2c-cp2615.c:296: adap = devm_kzalloc(&usbif->dev, sizeof(struct i2c_adapter), GFP_KERNEL);
drivers/i2c/busses/i2c-cp2615.c-297- if (!adap)
]
|
| 437/2 |
2026/07/30 13:23 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 113506
output: 49
thoughts: 39
Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience, presented in the first person:
**Initial Assessment: i2c-cp2615 - Ah, a USB I2C Adapter**
Right, so the `i2c-cp2615`β¦ that clicks immediately. It's a USB-to-I2C adapter, probably using the Silicon Labs CP2615 chip, from what I recall of the naming scheme. Always good to quickly identify the hardware in play. Now, let's dive into the details. I need to refresh my memory on the implementation. Let's start with `i2c-cp2615.c`. That should give a good overview of the driver's architecture, register mappings, and interaction with the underlying USB subsystem.
|
| 438/2 |
2026/07/30 13:24 |
tool |
read-file |
0m
Args: map[File:drivers/i2c/busses/i2c-cp2615.c FirstLine:280 LineCount:100]
Results: map[Contents: 280:
281: static int
282: cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id)
283: {
284: int ret = 0;
285: struct i2c_adapter *adap;
286: struct usb_device *usbdev = interface_to_usbdev(usbif);
287:
288: ret = usb_set_interface(usbdev, IOP_IFN, IOP_ALTSETTING);
289: if (ret)
290: return ret;
291:
292: ret = cp2615_check_iop(usbif);
293: if (ret)
294: return ret;
295:
296: adap = devm_kzalloc(&usbif->dev, sizeof(struct i2c_adapter), GFP_KERNEL);
297: if (!adap)
298: return -ENOMEM;
299:
300: if (!usbdev->serial)
301: return -EINVAL;
302:
303: strscpy(adap->name, usbdev->serial, sizeof(adap->name));
304: adap->owner = THIS_MODULE;
305: adap->dev.parent = &usbif->dev;
306: adap->dev.of_node = usbif->dev.of_node;
307: adap->timeout = HZ;
308: adap->algo = &cp2615_i2c_algo;
309: adap->quirks = &cp2615_i2c_quirks;
310: adap->algo_data = usbif;
311:
312: ret = i2c_add_adapter(adap);
313: if (ret)
314: return ret;
315:
316: usb_set_intfdata(usbif, adap);
317: return 0;
318: }
319:
320: static const struct usb_device_id id_table[] = {
321: { USB_DEVICE_INTERFACE_NUMBER(CP2615_VID, CP2615_PID, IOP_IFN) },
322: { }
323: };
324:
325: MODULE_DEVICE_TABLE(usb, id_table);
326:
327: static struct usb_driver cp2615_i2c_driver = {
328: .name = "i2c-cp2615",
329: .probe = cp2615_i2c_probe,
330: .disconnect = cp2615_i2c_disconnect,
331: .id_table = id_table,
332: };
333:
334: module_usb_driver(cp2615_i2c_driver);
335:
336: MODULE_AUTHOR("Bence CsΓ³kΓ‘s <bence98@sch.bme.hu>");
337: MODULE_DESCRIPTION("CP2615 I2C bus driver");
338: MODULE_LICENSE("GPL");
]
|
| 439/2 |
2026/07/30 13:24 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 114698
output: 48
thoughts: 82
Thoughts: **Memory Management Considerations in `cp2615_i2c_probe`**
Okay, hold on a second. I'm just looking over this `cp2615_i2c_probe` function, and my immediate thought is "Aha! `devm_kzalloc`!" That's a key detail. The use of `devm_kzalloc` is telling me that the allocated memory is *managed* by the device driver's resource management framework. This has significant implications for its lifecycle. Specifically, if `devm_kzalloc` is used, the allocated memory is automatically freed when the device is unbound. I know this because `devm_kzalloc` ties the memory to the lifetime of the device. That unbinding happens when the `usb_driver.disconnect` callback function returns, and the device is then released.
So, the next logical step here is to confirm this understanding, and to look at `cp2615_i2c_disconnect`. I need to verify that there isn't any redundant or contradictory memory management happening. I'm betting that the framework is handling the cleanup automatically, but I need to confirm this assumption. Let's see what's in there...
|
| 440/2 |
2026/07/30 13:24 |
tool |
read-file |
0m
Args: map[File:drivers/i2c/busses/i2c-cp2615.c FirstLine:270 LineCount:20]
Results: map[Contents: 270: .max_comb_2nd_msg_len = MAX_I2C_SIZE
271: };
272:
273: static void cp2615_i2c_disconnect(struct usb_interface *usbif)
274: {
275: struct i2c_adapter *adap = usb_get_intfdata(usbif);
276:
277: usb_set_intfdata(usbif, NULL);
278: i2c_del_adapter(adap);
279: }
280:
281: static int
282: cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id)
283: {
284: int ret = 0;
285: struct i2c_adapter *adap;
286: struct usb_device *usbdev = interface_to_usbdev(usbif);
287:
288: ret = usb_set_interface(usbdev, IOP_IFN, IOP_ALTSETTING);
289: if (ret)
]
|
| 441/2 |
2026/07/30 13:24 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 115420
output: 24
thoughts: 78
Thoughts: **Debugging the I2C Adapter Unregistration**
Okay, hold on a second. I need to re-evaluate what I just assumed. Looking back at the code, specifically at `cp2615_i2c_disconnect`, I see that it actually *does* call `i2c_del_adapter(adap)`. This means the I2C adapter *is* being unregistered properly before the memory is freed by `devm`. So, my initial hunch about the `cp2615` driver being the culprit is incorrect. That's a relief, but also means I'm back to square one.
Now, let's shift focus. What about the `i2c-diolan-u2c` driver? Could the issue lie there? I need to investigate that code path next.
|
| 442/2 |
2026/07/30 13:24 |
tool |
grepper |
0m
Args: map[Expression:kzalloc.*sizeof.*i2c_adapter]
Results: map[Output:drivers/i2c/busses/i2c-cbus-gpio.c=210=static int cbus_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-cbus-gpio.c-214-
drivers/i2c/busses/i2c-cbus-gpio.c:215: adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter),
drivers/i2c/busses/i2c-cbus-gpio.c-216- GFP_KERNEL);
--
drivers/i2c/busses/i2c-cp2615.c=282=cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id)
--
drivers/i2c/busses/i2c-cp2615.c-295-
drivers/i2c/busses/i2c-cp2615.c:296: adap = devm_kzalloc(&usbif->dev, sizeof(struct i2c_adapter), GFP_KERNEL);
drivers/i2c/busses/i2c-cp2615.c-297- if (!adap)
]
|
| 443/2 |
2026/07/30 13:24 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 116028
output: 23
thoughts: 4467
Thoughts: **Analyzing a Use-After-Free in the I2C Subsystem**
Okay, so I've got this UAF in the I2C code, specifically within `i2c_adapter_depth`, triggered by `i2c_adapter_lock_bus`. The initial clues are pointing me toward issues with the adapter object. It looks like `i2c_adapter_lock_bus` is indirectly being called from `i2cdev_ioctl_smbus`. That implies this is all coming from user space through an i2c device file.
I initially thought maybe the driver allocates a struct containing `i2c_adapter` as its *first* member, making the object size different than just `i2c_adapter`. But even a slightly larger object (2200 bytes) would still fall into the same `kmalloc-4k` pool. The UAF is specifically on a 4096-byte region. The bug report mentions an offset. The key is that the buggy address (264 bytes into the freed region) is offset from where `dev.parent` is, or where I *think* `dev.parent` is.
The crash is in `i2c_adapter_depth`, accessing `adapter->dev.parent`. Now, the crucial part is understanding what `parent->type` actually points to. The stack trace leads to `rt_mutex_lock_nested` which uses `i2c_adapter_depth`. That's where the problem arises: an access within a locked operation. The UAF must be happening *during* the parent traversal within `i2c_adapter_depth`.
I need to understand the memory layout of `i2c_adapter` and `device` precisely. I need to make sure I get the offset of `dev.parent` right. `dev` is at the offset of the fields before it which add up to around 192 bytes. `dev.parent` is at `192+ 64 = 256` because `kobject` (which is included in `dev`) is 64 bytes if `CONFIG_DEBUG_KOBJECT_RELEASE` is not enabled, and thus `dev.p` is at `192 + 72 = 264`.
The UAF is reported to be at offset 264 of a 4096 byte block. Thus, `dev.p` is being accessed.
The crucial thought comes next. If the access is to `parent->type`, then `parent` is a pointer to another object. If the object being read into `parent` is at 256, and the access is at 264, the read is accessing what should be in the `dev.p` field!
This must be a UAF of the pointer! Something is dereferencing `adapter->dev.parent`, which now contains a dangling pointer, leading to a read at the *reported* offset of 264. Now to figure out how `dev.p` ends up as a pointer to freed memory!
The allocation trace, however, shows that it was originally allocated for `sk_buff` data. That means this is a dangling pointer!
The key is in `i2cdev_ioctl`, which gets the `adapter` from a `client` structure associated with an i2c device file. This structure points to the `i2c_adapter` struct. It looks like it is obtained using `i2c_get_adapter(minor)`. If the `i2c_adapter` gets freed *after* the device file has been opened, but before it is closed, then the UAF can occur.
I now need to identify what 4096-byte object could contain an `i2c_adapter` *and* be freed prematurely.
|
| 444/2 |
2026/07/30 13:24 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:name OffsetBits:0 SizeBits:240] map[Name:model OffsetBits:256 SizeBits:32] map[Name:devno OffsetBits:288 SizeBits:32] map[Name:dev OffsetBits:320 SizeBits:64] map[Name:board OffsetBits:384 SizeBits:1984] map[Name:init_data OffsetBits:2368 SizeBits:448] map[Name:ir_i2c_client OffsetBits:2816 SizeBits:64] map[Name:stream_on OffsetBits:2880 SizeBits:1] map[Name:vbi_stream_on OffsetBits:2881 SizeBits:1] map[Name:has_audio_class OffsetBits:2882 SizeBits:1] map[Name:has_alsa_audio OffsetBits:2883 SizeBits:1] map[Name:i2c_scan_running OffsetBits:2884 SizeBits:1] map[Name:format OffsetBits:2944 SizeBits:64] map[Name:v4l2_dev OffsetBits:3008 SizeBits:1984] map[Name:sd_cx25840 OffsetBits:4992 SizeBits:64] map[Name:sd_tuner OffsetBits:5056 SizeBits:64] map[Name:ctrl_handler OffsetBits:5120 SizeBits:2432] map[Name:radio_ctrl_handler OffsetBits:7552 SizeBits:2432] map[Name:mpeg_ctrl_handler OffsetBits:9984 SizeBits:4672] map[Name:wq_trigger OffsetBits:14656 SizeBits:576] map[Name:stream_started OffsetBits:15232 SizeBits:32] map[Name:devlist OffsetBits:15296 SizeBits:128] map[Name:tuner_type OffsetBits:15424 SizeBits:32] map[Name:tuner_addr OffsetBits:15456 SizeBits:32] map[Name:i2c_bus OffsetBits:15488 SizeBits:51648] map[Name:muxc OffsetBits:67136 SizeBits:64] map[Name:i2c_mux_adap OffsetBits:67200 SizeBits:128] map[Name:xc_fw_load_done OffsetBits:67328 SizeBits:1] map[Name:port_3_switch_enabled OffsetBits:67329 SizeBits:1] map[Name:gpio_i2c_lock OffsetBits:67392 SizeBits:1024] map[Name:i2c_lock OffsetBits:68416 SizeBits:1024] map[Name:users OffsetBits:69440 SizeBits:32] map[Name:vdev OffsetBits:69504 SizeBits:16064] map[Name:norm OffsetBits:85568 SizeBits:64] map[Name:ctl_freq OffsetBits:85632 SizeBits:32] map[Name:ctl_ainput OffsetBits:85664 SizeBits:32] map[Name:width OffsetBits:85696 SizeBits:32] map[Name:height OffsetBits:85728 SizeBits:32] map[Name:interlaced OffsetBits:85760 SizeBits:32] map[Name:size OffsetBits:85792 SizeBits:32] map[Name:adev OffsetBits:85824 SizeBits:2752] map[Name:state OffsetBits:88576 SizeBits:32] map[Name:request_module_wk OffsetBits:88640 SizeBits:576] map[Name:lock OffsetBits:89216 SizeBits:1024] map[Name:ctrl_urb_lock OffsetBits:90240 SizeBits:1024] map[Name:inqueue OffsetBits:91264 SizeBits:128] map[Name:outqueue OffsetBits:91392 SizeBits:128] map[Name:open OffsetBits:91520 SizeBits:1152] map[Name:wait_frame OffsetBits:92672 SizeBits:1152] map[Name:wait_stream OffsetBits:93824 SizeBits:1152] map[Name:vbi_dev OffsetBits:94976 SizeBits:16064] map[Name:radio_dev OffsetBits:111040 SizeBits:16064] map[Name:media_dev OffsetBits:127104 SizeBits:64] map[Name:video_pad OffsetBits:127168 SizeBits:512] map[Name:vbi_pad OffsetBits:127680 SizeBits:512] map[Name:input_ent OffsetBits:128192 SizeBits:3840] map[Name:input_pad OffsetBits:132032 SizeBits:2048] map[Name:vidq OffsetBits:134080 SizeBits:5568] map[Name:vbiq OffsetBits:139648 SizeBits:5568] map[Name:eedata OffsetBits:145216 SizeBits:2048] map[Name:video_mode OffsetBits:147264 SizeBits:4480] map[Name:vbi_mode OffsetBits:151744 SizeBits:4480] map[Name:sliced_cc_mode OffsetBits:156224 SizeBits:4480] map[Name:ts1_mode OffsetBits:160704 SizeBits:4480] map[Name:devlist_count OffsetBits:165184 SizeBits:32] map[Name:udev OffsetBits:165248 SizeBits:64] map[Name:urb_buf OffsetBits:165312 SizeBits:640] map[Name:cx231xx_read_ctrl_reg OffsetBits:165952 SizeBits:64] map[Name:cx231xx_write_ctrl_reg OffsetBits:166016 SizeBits:64] map[Name:cx231xx_send_usb_command OffsetBits:166080 SizeBits:64] map[Name:cx231xx_gpio_i2c_read OffsetBits:166144 SizeBits:64] map[Name:cx231xx_gpio_i2c_write OffsetBits:166208 SizeBits:64] map[Name:cx231xx_set_analog_freq OffsetBits:166272 SizeBits:64] map[Name:cx231xx_reset_analog_tuner OffsetBits:166336 SizeBits:64] map[Name:mode OffsetBits:166400 SizeBits:32] map[Name:dvb OffsetBits:166464 SizeBits:64] map[Name:current_pcb_config OffsetBits:166528 SizeBits:608] map[Name:current_scenario_idx OffsetBits:167136 SizeBits:8] map[Name:interface_count OffsetBits:167144 SizeBits:8] map[Name:max_iad_interface_count OffsetBits:167152 SizeBits:8] map[Name:gpio_dir OffsetBits:167168 SizeBits:32] map[Name:gpio_val OffsetBits:167200 SizeBits:32] map[Name:power_mode OffsetBits:167232 SizeBits:32] map[Name:afe_mode OffsetBits:167264 SizeBits:32] map[Name:afe_ref_count OffsetBits:167296 SizeBits:32] map[Name:video_input OffsetBits:167328 SizeBits:32] map[Name:active_mode OffsetBits:167360 SizeBits:32] map[Name:vbi_or_sliced_cc_mode OffsetBits:167392 SizeBits:8] map[Name:std_mode OffsetBits:167424 SizeBits:32] map[Name:mode_tv OffsetBits:167456 SizeBits:8] map[Name:USE_ISO OffsetBits:167464 SizeBits:8] map[Name:encodernorm OffsetBits:167488 SizeBits:192] map[Name:ts1 OffsetBits:167680 SizeBits:2112] map[Name:ts2 OffsetBits:169792 SizeBits:2112] map[Name:mpegq OffsetBits:171904 SizeBits:5568] map[Name:v4l_device OffsetBits:177472 SizeBits:16064] map[Name:v4l_reader_count OffsetBits:193536 SizeBits:32] map[Name:freq OffsetBits:193568 SizeBits:32] map[Name:input OffsetBits:193600 SizeBits:32] map[Name:cx23417_mailbox OffsetBits:193632 SizeBits:32] map[Name:lmmio OffsetBits:193664 SizeBits:64] map[Name:bmmio OffsetBits:193728 SizeBits:64]]]
|
| 445/2 |
2026/07/30 13:24 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 123895
output: 37
thoughts: 3689
Thoughts: **Analyzing the UAF in `i2c_adapter_depth` and `i2c_adapter_lock_bus`**
Okay, so I'm digging into this Use-After-Free (UAF) issue in the I2C core, specifically within `i2c_adapter_depth` and `i2c_adapter_lock_bus`. The crash report points to an 8-byte read at address `0x108` (264) offset, and the goal is to understand what's happening at that specific memory location.
First, I need to figure out what's at offset 264 within the `struct i2c_adapter`. I know that the `struct i2c_adapter` itself, is allocated on the `kmalloc-4k`. I remember that `struct i2c_adapter` is allocated with `kzalloc`, so all members should be initialized. I calculated before that the size of `struct i2c_adapter` is 2128 bytes, which fits within `kmalloc-4k`.
I already calculated that `dev.parent` is at offset 256. But the bug is at offset 264.
I have to carefully consider the layout of `struct i2c_adapter` and how the `dev` member (a `struct device`) is positioned, particularly its `parent` member which is a pointer. If the size of `struct rt_mutex` is altered due to `CONFIG_LOCKDEP` or other factors, the offsets of subsequent members change. The assumption is that `dev.parent` is read, but something else might be going on, like `rt_mutex_lock_nested` also reading something at offset 264.
The code in `i2c_adapter_depth` is crucial: `parent = adapter->dev.parent; parent = parent->parent` and that reads `dev.parent` which is at offset 256. But the UAF is at offset 264. The potential read comes from `parent->type`. If the `parent` points to `&adapter->dev` then it might read the `dev.type`, which is at offset 280. I need to understand how `parent` is being corrupted to point to an invalid memory location or a freed object, leading to the UAF. The key must be in the `parent = adapter->dev.parent` assignment.
It's possible that the UAF isn't a direct read of `adapter->dev.parent`, which is at offset 256. It might be in the subsequent read of `parent->type`. If `adapter` is the freed object, then `adapter->dev.parent` is the address that was freed, and the crash should happen immediately when `parent` is read, since it should be invalid. But the read is not at offset 256, but at 264, which is the key.
Could the UAF be triggered in `rt_mutex_lock_nested` when it accesses the mutex? If so, does `rt_mutex_lock_nested` access offset 264 somehow? The address for bus_lock is at offset 40, so it should not read at offset 264.
I check `offsetof(struct i2c_adapter, dev)` again. It appears that `dev` is at 192, and therefore `dev.parent` is at `192 + 64 = 256`. The UAF occurs when reading at 264, so it's not the `dev.parent` but rather `dev.p`. But there is no field `p` in `dev`.
The important hint is, what is at 264? If `dev.parent` is at 256, is it possible for some other field to be at 264? My current structure calculation points to offset 256 (dev.parent) and a 64 bytes offset from that location. That is the size of `struct kobject`. Since `dev.parent` is actually a pointer to the `struct device` kobject, I now need to think about cases when `struct kobject` size is 72 bytes. The kobject size can be 72 bytes if `CONFIG_DEBUG_KOBJECT_RELEASE` is enabled. If it is, then `dev.parent` is at `192 + 72 = 264`. And that means there's a problem with kobject size calculation.
Now I have to rethink how `struct kobject` is constructed. It can be 64 bytes if `CONFIG_DEBUG_KOBJECT_RELEASE` is not set. Now, the new assumption is
|
| 446/2 |
2026/07/30 13:25 |
tool |
read-file |
0m
Args: map[File:include/linux/i2c.h FirstLine:700 LineCount:50]
Results: map[Contents: 700: struct i2c_adapter_quirks {
701: u64 flags;
702: int max_num_msgs;
703: u16 max_write_len;
704: u16 max_read_len;
705: u16 max_comb_1st_msg_len;
706: u16 max_comb_2nd_msg_len;
707: };
708:
709: /* enforce max_num_msgs = 2 and use max_comb_*_len for length checks */
710: #define I2C_AQ_COMB BIT(0)
711: /* first combined message must be write */
712: #define I2C_AQ_COMB_WRITE_FIRST BIT(1)
713: /* second combined message must be read */
714: #define I2C_AQ_COMB_READ_SECOND BIT(2)
715: /* both combined messages must have the same target address */
716: #define I2C_AQ_COMB_SAME_ADDR BIT(3)
717: /* convenience macro for typical write-then read case */
718: #define I2C_AQ_COMB_WRITE_THEN_READ (I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | \
719: I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR)
720: /* clock stretching is not supported */
721: #define I2C_AQ_NO_CLK_STRETCH BIT(4)
722: /* message cannot have length of 0 */
723: #define I2C_AQ_NO_ZERO_LEN_READ BIT(5)
724: #define I2C_AQ_NO_ZERO_LEN_WRITE BIT(6)
725: #define I2C_AQ_NO_ZERO_LEN (I2C_AQ_NO_ZERO_LEN_READ | I2C_AQ_NO_ZERO_LEN_WRITE)
726: /* adapter cannot do repeated START */
727: #define I2C_AQ_NO_REP_START BIT(7)
728:
729: /*
730: * i2c_adapter is the structure used to identify a physical i2c bus along
731: * with the access algorithms necessary to access it.
732: */
733: struct i2c_adapter {
734: struct module *owner;
735: unsigned int class; /* classes to allow probing for */
736: const struct i2c_algorithm *algo; /* the algorithm to access the bus */
737: void *algo_data;
738:
739: /* data fields that are valid for all devices */
740: const struct i2c_lock_operations *lock_ops;
741: struct rt_mutex bus_lock;
742: struct rt_mutex mux_lock;
743:
744: int timeout; /* in jiffies */
745: int retries;
746: struct device dev; /* the adapter device */
747: unsigned long locked_flags; /* owned by the I2C core */
748: #define I2C_ALF_IS_SUSPENDED 0
749: #define I2C_ALF_SUSPEND_REPORTED 1
]
|
| 447/2 |
2026/07/30 13:25 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 129606
output: 26
thoughts: 2606
Thoughts: **Analyzing the KASAN UAF in i2c_adapter_lock_bus**
Okay, so the initial confusion was about the offset of `dev.parent`. I initially thought it was at 192, but after checking the `codesearch-struct-layout` output for `i2c_adapter`, itβs actually at offset 304, meaning `dev.parent` is at 368. Still, the KASAN report indicates an access at offset 264. That doesn't add up... Now the question is what's at offset 264, or close to it? Digging deeper into `codesearch-struct-layout`, I found `mux_lock` starts at 168 bytes and is 128 bytes in size, thus, it goes up to 296 bytes. Therefore, offset 264 *is* within `mux_lock`, which is a `rt_mutex`. I need to figure out the layout of `rt_mutex`. It's comprised of a `rt_mutex_base` and a lockdep map, or a `dep_map`. Since `rt_mutex` is 128 bytes, and `rt_mutex_base` is 84 bytes plus some padding, the `dep_map` must begin at offset 88. And `lockdep_map` is made of some pointers and string constants.
Okay, back to the problem: the UAF is at offset 264. I was initially focused on how the `i2c_adapter` itself is structured, but now I'm thinking the bug lies in how the object referenced by `adapter->dev.parent` is structured. The key here is *why* the read is happening at offset 264 *inside* the structure, which is not what `i2c_adapter_lock_bus` should be touching! The code accessing the potentially freed object is in `i2c_adapter_depth`. And there, the code iterates up the device tree via `parent = adapter->dev.parent; parent = parent->parent;`. What's the assumption here? That the `parent` fields are intact. The report says the UAF is at 264, but no fields within i2c_adapter are near 264.
What if *`adapter->dev.parent`* is the freed object, meaning it's been corrupted, or is pointing to a freed object. Then reading into a freed object could generate the KASAN report, but 264 is the mystery. If `adapter->dev.parent` points to the freed object, then `parent` becomes the freed object. If so, and we attempt to read `parent->type`, that's at offset 88, which is not 264. Perhaps it is `parent->parent` at offset 64, this still doesn't explain the 264. The report says the UAF read is at `i2c_adapter_depth` line 1243. The read is `parent = parent->parent` at 64 bytes.
Now I am thinking that `adapter` is not a `struct i2c_adapter` itself. But it is passed to a function that uses fields in a `struct i2c_adapter`. What if `adapter->dev.parent` points to something else? What if it's pointing to the freed object? What is that freed object, and what is *in* it at offset 264?
I know `go7007` is allocated with `kzalloc(sizeof(struct go7007)`, and that is 8522 bytes, so kmalloc-16k, it can not be the object. And `au0828_dev` is allocated with kzalloc as well, and it is also way bigger than 4096.
Could it be that the freed object is `struct i2c_adapter`? I need to look for `kzalloc` of `i2c_adapter` without freeing it properly, but I am finding instances that use `devm_kzalloc`, which should handle the freeing properly!
I need to search more broadly, and specifically for allocation and *use* to track down what this freed object is!
|
| 448/2 |
2026/07/30 13:25 |
tool |
grepper |
0m
Args: map[Expression:kzalloc.*sizeof.*\b(adapter|adap)\b]
Results: map[Output:drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c=287=int sun4i_hdmi_i2c_create(struct device *dev, struct sun4i_hdmi *hdmi)
--
drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c-299-
drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c:300: adap = devm_kzalloc(dev, sizeof(*adap), GFP_KERNEL);
drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c-301- if (!adap)
--
drivers/i2c/busses/i2c-cht-wc.c=426=static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-cht-wc.c-436-
drivers/i2c/busses/i2c-cht-wc.c:437: adap = devm_kzalloc(&pdev->dev, sizeof(*adap), GFP_KERNEL);
drivers/i2c/busses/i2c-cht-wc.c-438- if (!adap)
--
drivers/i2c/busses/i2c-opal.c=196=static int i2c_opal_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-opal.c-211-
drivers/i2c/busses/i2c-opal.c:212: adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
drivers/i2c/busses/i2c-opal.c-213- if (!adapter)
--
drivers/media/platform/amlogic/c3/mipi-adapter/c3-mipi-adap.c=762=static int c3_mipi_adap_probe(struct platform_device *pdev)
--
drivers/media/platform/amlogic/c3/mipi-adapter/c3-mipi-adap.c-767-
drivers/media/platform/amlogic/c3/mipi-adapter/c3-mipi-adap.c:768: adap = devm_kzalloc(dev, sizeof(*adap), GFP_KERNEL);
drivers/media/platform/amlogic/c3/mipi-adapter/c3-mipi-adap.c-769- if (!adap)
--
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c=6571=static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
--
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c-6636- adapter->msg_enable = DFLT_MSG_ENABLE;
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c:6637: adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) +
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c-6638- (sizeof(struct mbox_cmd) *
--
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c=2895=static int cxgb4vf_pci_probe(struct pci_dev *pdev,
--
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c-2946-
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c:2947: adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) +
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c-2948- (sizeof(struct mbox_cmd) *
--
drivers/net/ethernet/ibm/ehea/ehea_main.c=3366=static int ehea_probe_adapter(struct platform_device *dev)
--
drivers/net/ethernet/ibm/ehea/ehea_main.c-3381-
drivers/net/ethernet/ibm/ehea/ehea_main.c:3382: adapter = devm_kzalloc(&dev->dev, sizeof(*adapter), GFP_KERNEL);
drivers/net/ethernet/ibm/ehea/ehea_main.c-3383- if (!adapter) {
--
drivers/net/ethernet/ibm/ibmveth.c=2204=static void ibmveth_remove_buffer_from_pool_test(struct kunit *test)
drivers/net/ethernet/ibm/ibmveth.c-2205-{
drivers/net/ethernet/ibm/ibmveth.c:2206: struct ibmveth_adapter *adapter = kunit_kzalloc(test, sizeof(*adapter), GFP_KERNEL);
drivers/net/ethernet/ibm/ibmveth.c-2207- struct ibmveth_buff_pool *pool;
--
drivers/net/ethernet/ibm/ibmveth.c=2250=static void ibmveth_rxq_get_buffer_test(struct kunit *test)
drivers/net/ethernet/ibm/ibmveth.c-2251-{
drivers/net/ethernet/ibm/ibmveth.c:2252: struct ibmveth_adapter *adapter = kunit_kzalloc(test, sizeof(*adapter), GFP_KERNEL);
drivers/net/ethernet/ibm/ibmveth.c-2253- struct sk_buff *skb = kunit_kzalloc(test, sizeof(*skb), GFP_KERNEL);
--
drivers/usb/misc/usb-ljca.c=753=static int ljca_probe(struct usb_interface *interface,
--
drivers/usb/misc/usb-ljca.c-762-
drivers/usb/misc/usb-ljca.c:763: adap = devm_kzalloc(dev, sizeof(*adap), GFP_KERNEL);
drivers/usb/misc/usb-ljca.c-764- if (!adap)
]
|
| 449/2 |
2026/07/30 13:25 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 134754
output: 40
thoughts: 28
Thoughts: Okay, here's my take on those thoughts, framed as my own:
**Digging into the `usb-ljca.c` Source**
Alright, hold on a second. It just hit me... doesn't `usb-ljca.c` handle the allocation of the `adap` structure? I need to verify this assumption. Let's fire up the source code for `usb-ljca.c` and make sure my memory is serving me correctly. That's a critical piece of the puzzle, and I need to be absolutely certain before I move forward. Gotta double-check those fundamentals!
|
| 450/2 |
2026/07/30 13:25 |
tool |
read-file |
0m
Args: map[File:drivers/usb/misc/usb-ljca.c FirstLine:750 LineCount:50]
Results: map[Contents: 750: return ret;
751: }
752:
753: static int ljca_probe(struct usb_interface *interface,
754: const struct usb_device_id *id)
755: {
756: struct usb_device *usb_dev = interface_to_usbdev(interface);
757: struct usb_host_interface *alt = interface->cur_altsetting;
758: struct usb_endpoint_descriptor *ep_in, *ep_out;
759: struct device *dev = &interface->dev;
760: struct ljca_adapter *adap;
761: int ret;
762:
763: adap = devm_kzalloc(dev, sizeof(*adap), GFP_KERNEL);
764: if (!adap)
765: return -ENOMEM;
766:
767: /* separate tx buffer allocation for alignment */
768: adap->tx_buf = devm_kzalloc(dev, LJCA_MAX_PACKET_SIZE, GFP_KERNEL);
769: if (!adap->tx_buf)
770: return -ENOMEM;
771: adap->tx_buf_len = LJCA_MAX_PACKET_SIZE;
772:
773: mutex_init(&adap->mutex);
774: spin_lock_init(&adap->lock);
775: init_completion(&adap->cmd_completion);
776: INIT_LIST_HEAD(&adap->client_list);
777:
778: adap->intf = interface;
779: adap->usb_dev = usb_dev;
780: adap->dev = dev;
781:
782: /*
783: * find the first bulk in and out endpoints.
784: * ignore any others.
785: */
786: ret = usb_find_common_endpoints(alt, &ep_in, &ep_out, NULL, NULL);
787: if (ret) {
788: dev_err(dev, "bulk endpoints not found\n");
789: goto err_destroy_mutex;
790: }
791: adap->rx_pipe = usb_rcvbulkpipe(usb_dev, usb_endpoint_num(ep_in));
792: adap->tx_pipe = usb_sndbulkpipe(usb_dev, usb_endpoint_num(ep_out));
793:
794: /* setup rx buffer */
795: adap->rx_len = usb_endpoint_maxp(ep_in);
796: adap->rx_buf = devm_kzalloc(dev, adap->rx_len, GFP_KERNEL);
797: if (!adap->rx_buf) {
798: ret = -ENOMEM;
799: goto err_destroy_mutex;
]
|
| 451/2 |
2026/07/30 13:25 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 135767
output: 20
thoughts: 177
Thoughts: **Debugging the `go7007` Driver**
Okay, hold on a second... I was operating under the assumption that `ljca_adapter` and `i2c_adapter` were the same thing. They're not. That's a misdirection. Let's refocus on that `go7007` bug we were looking at. I'm practically certain the problem stems from the `go7007_usb_probe` function. It seems like it's failing during allocation and hitting `allocfail`, which then leads to `go` getting freed *before* the `i2c_adapter` is unregistered. That's a classic race condition and likely memory corruption.
But wait a minuteβ¦ the size reported by KASAN doesnβt match what I expect! The `go7007` structure is supposed to be 8524 bytes, but KASAN's reporting it as 4096 bytes? Could the `go7007` struct have been split into multiple allocations somehow? No, `go = kzalloc_obj(struct go7007);` explicitly allocates the entire struct in a single call.
Wait, the clue is in `kzalloc_obj`! Let's check that. Perhaps `kzalloc_obj` isn't behaving as I expect. It's time to dive into that function and understand its behavior in detail.
|
| 452/2 |
2026/07/30 13:26 |
tool |
grepper |
0m
Args: map[Expression:#define kzalloc_obj]
Results: map[Output:include/linux/slab.h=1070=void *kmalloc_nolock(size_t size, gfp_t gfp_flags, int node);
--
include/linux/slab.h-1151-/* All kzalloc aliases for kmalloc_(obj|objs|flex). */
include/linux/slab.h:1152:#define kzalloc_obj(P, ...) \
include/linux/slab.h-1153- __alloc_objs(kzalloc, default_gfp(__VA_ARGS__), typeof(P), 1)
include/linux/slab.h:1154:#define kzalloc_objs(P, COUNT, ...) \
include/linux/slab.h-1155- __alloc_objs(kzalloc, default_gfp(__VA_ARGS__), typeof(P), COUNT)
--
tools/include/linux/slab.h=200=static inline unsigned int kmem_cache_sheaf_size(struct slab_sheaf *sheaf)
--
tools/include/linux/slab.h-210-
tools/include/linux/slab.h:211:#define kzalloc_obj(P, ...) \
tools/include/linux/slab.h-212- __alloc_objs(kzalloc, default_gfp(__VA_ARGS__), typeof(P), 1)
]
|
| 453/2 |
2026/07/30 13:26 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 136604
output: 50
thoughts: 1088
Thoughts: **Debugging a Suspected UAF in USB Driver Code**
Okay, here's what's running through my head. KASAN reported a potential use-after-free issue, and I'm trying to trace it down. First, I'm thinking about the allocation size. `kzalloc_obj(struct go7007)` *should* allocate `sizeof(struct go7007)`, which based on the initial calculation using the interrupt data offset, *should* be 8522 bytes and go into a `kmalloc-16k` slab. But KASAN flagged `kmalloc-4k`, which doesn't make sense. It is probably not `struct go7007`, or at least not what I initially thought. I need to make sure about the structure size. No `#ifdef` affects `struct go7007` so it should be a constant size, but I need to make sure.
Is it possible it is `struct go7007_usb`? No, that's tiny. What about an `i2c_adapter` allocated by `i2c_add_adapter`? No, `i2c_add_adapter` *doesn't* allocate it, it takes a pointer. And `i2c_client` is also small. Okay, so that's not it.
Let's shift gears. Could the problem be in the `au0828` driver? I'm looking at `au0828_usb_disconnect`. The key here seems to be the conditional flow after `au0828_analog_unregister`. If it returns 1, `v4l2_device_put(&dev->v4l2_dev)` is called. If that drops the last reference, `au0828_usb_v4l2_release` is called, which calls `au0828_usb_release(dev)`. That's the normal path. But what if it *doesn't* drop the last reference? Then `au0828_usb_release(dev)` isn't called, which means `dev` *isn't* freed. However, I think the USB device *is* being disconnected and presumably its resources freed even if `dev` remains. So, there shouldn't be a UAF of `dev`. Now, if `dev` isn't freed, and `dev->usbdev` is set to NULL, and the `i2c_adapter` isn't freed either, there's no UAF of the `i2c_adapter` as well.
But, if `v4l2_device_put` *does* drop the last reference, and `au0828_usb_release(dev)` is called... Then `dev` *is* freed! In `au0828_usb_release` the `au0828_i2c_unregister(dev)` function will get called, and that calls `i2c_del_adapter(&dev->i2c_adap)`. So, the `i2c_adapter` *is* unregistered *before* `dev` is freed. Seems safe. This is good.
So, let me check the `cx231xx` driver just in case. I need to look at `cx231xx_usb_disconnect` to see how it handles things...
|
| 454/2 |
2026/07/30 13:26 |
tool |
read-file |
0m
Args: map[File:drivers/media/usb/cx231xx/cx231xx-cards.c FirstLine:1800 LineCount:50]
Results: map[Contents:1800: dev_dbg(d, "registering interface %d\n", ifnum);
1801:
1802: /* save our data pointer in this interface device */
1803: usb_set_intfdata(interface, dev);
1804:
1805: /* Initialize the media controller */
1806: retval = cx231xx_media_device_init(dev, udev);
1807: if (retval) {
1808: dev_err(d, "cx231xx_media_device_init failed\n");
1809: goto err_media_init;
1810: }
1811:
1812: /* Create v4l2 device */
1813: #ifdef CONFIG_MEDIA_CONTROLLER
1814: dev->v4l2_dev.mdev = dev->media_dev;
1815: #endif
1816: retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
1817: if (retval) {
1818: dev_err(d, "v4l2_device_register failed\n");
1819: goto err_v4l2;
1820: }
1821:
1822: /* allocate device struct */
1823: retval = cx231xx_init_dev(dev, udev, nr);
1824: if (retval)
1825: goto err_init;
1826:
1827: retval = cx231xx_init_v4l2(dev, udev, interface, isoc_pipe);
1828: if (retval)
1829: goto err_init;
1830:
1831: if (dev->current_pcb_config.ts1_source != 0xff) {
1832: /* compute alternate max packet sizes for TS1 */
1833: idx = dev->current_pcb_config.hs_config_info[0].interface_info.ts1_index + 1;
1834: if (idx >= dev->max_iad_interface_count) {
1835: dev_err(d, "TS1 PCB interface #%d doesn't exist\n",
1836: idx);
1837: retval = -ENODEV;
1838: goto err_video_alt;
1839: }
1840: uif = udev->actconfig->interface[idx];
1841:
1842: if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) {
1843: retval = -ENODEV;
1844: goto err_video_alt;
1845: }
1846:
1847: dev->ts1_mode.end_point_addr =
1848: uif->altsetting[0].endpoint[isoc_pipe].
1849: desc.bEndpointAddress;
]
|
| 455/2 |
2026/07/30 13:26 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 139313
output: 22
thoughts: 229
Thoughts: **Investigating the Memory Footprint of `cx231xx`**
Okay, so I was under the impression that `cx231xx` was a 4096-byte object, but wait a minute, that's not right. The size, 193792 bits, actually translates to a significantly larger 24224 bytes. That's a huge discrepancy! I need to figure out what's going on.
Let's think through this systematically. Could this large object be a `struct i2c_adapter` allocated by `i2c_add_adapter`? No, that's incorrect. `i2c_add_adapter` doesn't allocate the `struct i2c_adapter` itself; it's a different mechanism. Okay, let's consider another common I2C structure. What if the object is a `struct i2c_client`? No, that's too small. The memory footprint wouldn't be this large. Okay... perhaps a `struct i2c_dev`?
Looking at the definition:
```c
struct i2c_dev {
struct list_head list;
struct i2c_adapter *adap;
struct device *dev;
struct cdev cdev;
};
```
That doesn't seem right either. `i2c_dev` is definitely a small structure. Hmm, what else could it be...wait, what if it's a `struct nsim_dev`? That seems like a reasonable possibility. Let's check the size of `sizeof(struct nsim_dev)` to see if it matches the value I'm seeing for `cx231xx`.
|
| 456/2 |
2026/07/30 13:26 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:nsim_bus_dev OffsetBits:0 SizeBits:64] map[Name:fib_data OffsetBits:64 SizeBits:64] map[Name:trap_data OffsetBits:128 SizeBits:64] map[Name:ddir OffsetBits:192 SizeBits:64] map[Name:ports_ddir OffsetBits:256 SizeBits:64] map[Name:take_snapshot OffsetBits:320 SizeBits:64] map[Name:nodes_ddir OffsetBits:384 SizeBits:64] map[Name:vfconfigs OffsetBits:448 SizeBits:64] map[Name:bpf_dev OffsetBits:512 SizeBits:64] map[Name:bpf_bind_accept OffsetBits:576 SizeBits:8] map[Name:bpf_bind_verifier_accept OffsetBits:584 SizeBits:8] map[Name:bpf_bind_verifier_delay OffsetBits:608 SizeBits:32] map[Name:ddir_bpf_bound_progs OffsetBits:640 SizeBits:64] map[Name:prog_id_gen OffsetBits:704 SizeBits:32] map[Name:bpf_bound_progs OffsetBits:768 SizeBits:128] map[Name:bpf_bound_maps OffsetBits:896 SizeBits:128] map[Name:progs_list_lock OffsetBits:1024 SizeBits:1024] map[Name:switch_id OffsetBits:2048 SizeBits:264] map[Name:port_list OffsetBits:2368 SizeBits:128] map[Name:fw_update_status OffsetBits:2496 SizeBits:8] map[Name:fw_update_overwrite_mask OffsetBits:2528 SizeBits:32] map[Name:fw_update_flash_chunk_time_ms OffsetBits:2560 SizeBits:32] map[Name:max_macs OffsetBits:2592 SizeBits:32] map[Name:test1 OffsetBits:2624 SizeBits:8] map[Name:test2 OffsetBits:2656 SizeBits:32] map[Name:dont_allow_reload OffsetBits:2688 SizeBits:8] map[Name:fail_reload OffsetBits:2696 SizeBits:8] map[Name:dummy_region OffsetBits:2752 SizeBits:64] map[Name:health OffsetBits:2816 SizeBits:320] map[Name:hwstats OffsetBits:3136 SizeBits:2816] map[Name:fa_cookie OffsetBits:5952 SizeBits:64] map[Name:fa_cookie_lock OffsetBits:6016 SizeBits:1024] map[Name:fail_trap_group_set OffsetBits:7040 SizeBits:8] map[Name:fail_trap_policer_set OffsetBits:7048 SizeBits:8] map[Name:fail_trap_policer_counter_get OffsetBits:7056 SizeBits:8] map[Name:fail_trap_drop_counter_get OffsetBits:7064 SizeBits:8] map[Name:udp_ports OffsetBits:7104 SizeBits:512] map[Name:psample OffsetBits:7616 SizeBits:64] map[Name:esw_mode OffsetBits:7680 SizeBits:16]]]
|
| 457/2 |
2026/07/30 13:26 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 140866
output: 24
thoughts: 4224
Thoughts: **Analyzing a Suspected Use-After-Free in the I2C Subsystem**
Okay, so I'm digging into this KASAN report and trying to understand this use-after-free in the I2C subsystem. First, the memory block size: it's *not* the 4096 bytes I initially thought, it's 962 bytes. But wait, it's a `sk_buff` data allocation, 4096 bytes! This means this memory used to be *sk_buff* data, then freed, and *then* reallocated as something else before being freed again, right? But KASAN only reports the LAST allocation and free. If it *was* reallocated and then freed, KASAN would report the allocation of the *reallocated* object. Since KASAN reports the `sk_buff` data allocation, the memory wasn't reallocated after all!
The key is a *dangling pointer*. An `i2c_adapter` pointer is somehow accessing memory that was allocated as `sk_buff` data and was subsequently freed. A `use-after-free` of a struct containing an `i2c_adapter` pointer. `i2c_adapter_lock_bus` uses `struct i2c_adapter *adapter`. The trace leads to `i2cdev_ioctl`, which gets the `adapter` from `client->adapter` where `client` is `file->private_data`.
If `client->adapter` is pointing to the freed `sk_buff` data, either `client` is corrupted, or it's *itself* in the freed `sk_buff` data! If `client` is in the freed data, then `file->private_data` points to the freed `sk_buff` data. How could that happen? Maybe it's a file descriptor set by *another* driver and passed to `i2cdev_ioctl`? But `i2cdev_ioctl` is specifically for `/dev/i2c-X`, so the file descriptor *must* be valid for an I2C device.
`i2cdev_open` is what sets `file->private_data`, using a `kzalloc`'d `i2c_client`. `sizeof(struct i2c_client)` is small, so it *cannot* be the freed object. Therefore, `client->adapter` *must* be the dangling pointer to the freed `sk_buff` data. In `i2cdev_open`, `client->adapter` is set to `adap`, which comes from `i2c_get_adapter(minor)`. `i2c_get_adapter` gets the `i2c_adapter` from `i2c_adapter_idr`.
Aha! If the `i2c_adapter` was freed *without* being removed from the `i2c_adapter_idr`, `i2c_get_adapter` would return a dangling pointer! `i2c_add_adapter` puts it in the IDR. If a driver frees the adapter *without* calling `i2c_del_adapter`, the dangling pointer remains in the IDR. When userspace opens `/dev/i2c-X`, `i2c_get_adapter` finds the dangling pointer!
The mutex protection in `i2c_get_adapter` is important. It uses `try_module_get` on `adapter->owner` and then `get_device` to access `adapter->dev.kobj.kref`. If the freed memory has `NULL` at the `owner` offset, `try_module_get` succeeds! Then `get_device` would be called. If the memory *was* reallocated as `sk_buff`, the `owner` member (at offset 0) would be NULL. But KASAN did *not* catch anything.
The clue here is *when* the memory was freed. It's when `i2c_get_adapter` is *called* that the memory has *not* been freed yet. *Then*, the allocation is `sk_buff` data. The memory allocation trace now makes sense! `i2c_get_adapter` reads the garbage from `sk_buff`, then `get_device` does it's work, which could modify the kref in the freed data! Then the `sk_buff` *is* freed! `i2cdev_ioctl` then attempts to access the now-freed data. *That* is the KASAN report!
The key here is that the driver has freed the `i2c_adapter` *without* calling `
|
| 458/2 |
2026/07/30 13:27 |
tool |
grepper |
0m
Error:
Args: map[Expression:i2c_add_adapter.*allocfail]
Results:
|
| 459/2 |
2026/07/30 13:27 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 146153
output: 28
thoughts: 24
Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience, and delivered as a first-person summary:
**Digging into I2C Adapter Driver Interactions**
Alright, I'm thinking I need to understand this driver better, specifically how it's managing its resources. I'm going to search for a specific pattern of function calls that are usually good indicators of potential issues or areas for deeper scrutiny. I'm going to look for instances where both `i2c_add_adapter` and `kfree` appear within the *same* function body. The `i2c_add_adapter` is the crucial call that registers the I2C adapter with the kernel, so I'm suspecting that I need to investigate the cleanup process, especially if memory is being allocated, then freed at that point. The use of `kfree` strongly suggests dynamic memory management is in play, so I want to know exactly how they are coupled: is the memory allocated when adding the adapter, and subsequently freed if the adapter is removed? Are there any obvious potential double-free scenarios or memory leaks if, say, the adapter initialization fails and the `i2c_add_adapter` never succeeds? I want to see *how* these two calls interact to find any areas that might warrant a closer look.
|
| 460/2 |
2026/07/30 13:27 |
tool |
grepper |
0m
Error:
Args: map[Expression:i2c_add_adapter.*\n.*\n.*kfree]
Results:
|
| 461/2 |
2026/07/30 13:27 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 146496
output: 25
thoughts: 23
Thoughts: Okay, here's my thought process summarized from the prompt, as if it were my own:
**Investigating Potential Code Issues**
Alright, I need to dig into some code. I have a hunch there might be some problematic control flow going on, specifically related to how an I2C adapter is added. My initial instinct is to look for a specific pattern: functions that call `i2c_add_adapter` *and* use `goto` statements within the same scope. The combination of those two elements often suggests a possible issue with resource management, error handling, or overall code clarity. I'm thinking perhaps a `goto` could bypass crucial cleanup steps in the event of an error during adapter addition, or maybe itβs just a symptom of poorly structured logic. Time to get my hands dirty and start searching.
|
| 462/2 |
2026/07/30 13:27 |
tool |
grepper |
0m
Error:
Args: map[Expression:i2c_add_adapter.*\n.*goto]
Results:
|
| 463/2 |
2026/07/30 13:27 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 146730
output: 33
thoughts: 104
Thoughts: **Debugging a Kernel Driver I2C Initialization**
Okay, so I'm chasing down this error, and it's got me thinking. `i2c_add_adapter` is supposed to return an error code, right? So the typical pattern I'd expect to see is:
```c
ret = i2c_add_adapter(&dev->i2c_adapter);
if (ret)
goto err;
```
Pretty standard stuff. But here's the kicker: I'm specifically looking for a `goto` statement that appears *after* `i2c_add_adapter` *succeeds*. That's the unusual part. That's what I need to understand, since this is a kernel issue. Itβs got my brain ticking. Letβs not overthink this β letβs go broad. Time to check `drivers/media/usb/` directory. Maybe that module is a reasonable place to start, given the USB context. Let's see whatβs going on in those drivers. Iβll bet I can find some clues there.
|
| 464/2 |
2026/07/30 13:27 |
tool |
grepper |
0m
Args: map[Expression:i2c_add_adapter PathPrefix:drivers/media/usb/]
Results: map[Output:drivers/media/usb/au0828/au0828-i2c.c=354=int au0828_i2c_register(struct au0828_dev *dev)
--
drivers/media/usb/au0828/au0828-i2c.c-373-#endif
drivers/media/usb/au0828/au0828-i2c.c:374: i2c_add_adapter(&dev->i2c_adap);
drivers/media/usb/au0828/au0828-i2c.c-375-
--
drivers/media/usb/cx231xx/cx231xx-i2c.c=514=int cx231xx_i2c_register(struct cx231xx_i2c *bus)
--
drivers/media/usb/cx231xx/cx231xx-i2c.c-527- i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
drivers/media/usb/cx231xx/cx231xx-i2c.c:528: bus->i2c_rc = i2c_add_adapter(&bus->i2c_adap);
drivers/media/usb/cx231xx/cx231xx-i2c.c-529-
--
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c=56=static int dvb_usbv2_i2c_init(struct dvb_usb_device *d)
--
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c-68-
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c:69: ret = i2c_add_adapter(&d->i2c_adap);
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c-70- if (ret < 0) {
--
drivers/media/usb/dvb-usb/dvb-usb-i2c.c=11=int dvb_usb_i2c_init(struct dvb_usb_device *d)
--
drivers/media/usb/dvb-usb/dvb-usb-i2c.c-30-
drivers/media/usb/dvb-usb/dvb-usb-i2c.c:31: ret = i2c_add_adapter(&d->i2c_adap);
drivers/media/usb/dvb-usb/dvb-usb-i2c.c-32- if (ret < 0) {
--
drivers/media/usb/em28xx/em28xx-i2c.c=970=int em28xx_i2c_register(struct em28xx *dev, unsigned int bus,
--
drivers/media/usb/em28xx/em28xx-i2c.c-991-
drivers/media/usb/em28xx/em28xx-i2c.c:992: retval = i2c_add_adapter(&dev->i2c_adap[bus]);
drivers/media/usb/em28xx/em28xx-i2c.c-993- if (retval < 0) {
drivers/media/usb/em28xx/em28xx-i2c.c-994- dev_err(&dev->intf->dev,
drivers/media/usb/em28xx/em28xx-i2c.c:995: "%s: i2c_add_adapter failed! retval [%d]\n",
drivers/media/usb/em28xx/em28xx-i2c.c-996- __func__, retval);
--
drivers/media/usb/go7007/go7007-i2c.c=204=int go7007_i2c_init(struct go7007 *go)
--
drivers/media/usb/go7007/go7007-i2c.c-209- i2c_set_adapdata(&go->i2c_adapter, go);
drivers/media/usb/go7007/go7007-i2c.c:210: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
drivers/media/usb/go7007/go7007-i2c.c-211- dev_err(go->dev,
drivers/media/usb/go7007/go7007-i2c.c:212: "go7007-i2c: error: i2c_add_adapter failed\n");
drivers/media/usb/go7007/go7007-i2c.c-213- return -1;
--
drivers/media/usb/go7007/go7007-usb.c=1040=static int go7007_usb_probe(struct usb_interface *intf,
--
drivers/media/usb/go7007/go7007-usb.c-1171- i2c_set_adapdata(&go->i2c_adapter, go);
drivers/media/usb/go7007/go7007-usb.c:1172: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
drivers/media/usb/go7007/go7007-usb.c:1173: dev_err(go->dev, "error: i2c_add_adapter failed\n");
drivers/media/usb/go7007/go7007-usb.c-1174- goto allocfail;
--
drivers/media/usb/hdpvr/hdpvr-i2c.c=180=int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
--
drivers/media/usb/hdpvr/hdpvr-i2c.c-188-
drivers/media/usb/hdpvr/hdpvr-i2c.c:189: return i2c_add_adapter(&dev->i2c_adapter);
drivers/media/usb/hdpvr/hdpvr-i2c.c-190-}
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c=591=void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
--
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-627- i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c:628: i2c_add_adapter(&hdw->i2c_adap);
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c-629- if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
--
drivers/media/usb/stk1160/stk1160-i2c.c=247=int stk1160_i2c_register(struct stk1160 *dev)
--
drivers/media/usb/stk1160/stk1160-i2c.c-257-
drivers/media/usb/stk1160/stk1160-i2c.c:258: rc = i2c_add_adapter(&dev->i2c_adap);
drivers/media/usb/stk1160/stk1160-i2c.c-259- if (rc < 0) {
--
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c=1597=static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
--
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c-1655-
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c:1656: result = i2c_add_adapter(&ttusb->i2c_adap);
drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c-1657- if (result)
]
|
| 465/2 |
2026/07/30 13:27 |
llm |
crash-repro-finder |
2m
Model:
Tokens:
input: 149304
output: 246
thoughts: 16398
Thoughts: **The Hunt for the Elusive UAF: A Journey Through USB and I2C**
Alright, buckle up, because I've been chasing a KASAN slab-use-after-free bug, and it's a wild ride. The initial clue points me towards `i2c_adapter_depth` function, which is reading memory it shouldn't. The real problem is likely not in this specific function but in the sequence of events that leads to this access.
First things first, I needed to figure out *which* I2C driver caused this UAF. I began by looking at all of the drivers which register an I2C adapter using `i2c_add_adapter` but potentially free the memory without removing the adapter. Scanning the code, I honed in on `go7007`, a USB-based video capture device. It turns out that `go7007` adds the I2C adapter but has a `goto allocfail` path that *skips* the unregistration of the I2C adapter under certain error conditions. This looks suspicious. It's the perfect setup for a use-after-free!
My next step: confirm that the `go7007` driver is responsible. To do so, I traced the memory allocation and potential free of the driver's struct. I made my calculations, the driver struct should be allocated from kmalloc-4k. I then reviewed KASAN reports and kernel configs. It appeared that, under particular configurations, the struct would indeed fit into a kmalloc-4k slab.
I then dug into the kernel code to find what was being freed after a call to `i2c_add_adapter` and which function was reading from the freed memory. The `go7007` driver calls `i2c_add_adapter` during its USB probe, and this call *succeeds*. After the adapter is registered, it checks for the existence of an endpoint, and if the endpoint is *not* present it frees the memory that contains the I2C adapter without removing it from the I2C subsystem.
From this insight, I put together the pieces to trigger a USB-related error during the `go7007_usb_probe` process. I hypothesized and confirmed that by crafting a specific USB device descriptor that omits an endpoint, I can force the `go7007` driver into the `allocfail` path. Doing so, it allocates an I2C adapter, registers it, and then frees the struct containing the adapter, but the adapter is still present within the I2C system. Then, when a user accesses `/dev/i2c-X` for that device, the UAF would occur when it attempts to call the function `i2c_adapter_depth`. I set out to construct a USB descriptor that would trigger the UAF.
Thus, my plan is to craft the specific USB descriptors that will trigger the bug, so that the I2C adapter remains registered, even though the driver's struct (and with it, the I2C adapter's underlying memory) is freed. Finally, I write a syzkaller program to trigger it. The syzkaller program will first connect the USB device, and then open `/dev/i2c-X` and perform an I2C transfer.
Bingo! That should do the trick! Now to translate this plan into a working testcase.
|
| 466/2 |
2026/07/30 13:29 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, AUTO, &AUTO={0, &AUTO="12010002000000403b0904a10100000000010902200001010080000904000002ff00ff000705840340000107058802400000", 0, 0, &AUTO=[{0x84, &AUTO="0000aa55"}]}, 0)
r1 = syz_open_dev$i2c(&AUTO='/dev/i2c-#\x00', 0, 0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, &AUTO=""})
Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 467/2 |
2026/07/30 13:29 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 166861
output: 248
thoughts: 494
Thoughts: **Dissecting the `syz_usb_connect` Call**
Okay, so I'm looking at this `syz_usb_connect` call, and the key here is the `vusb_dev` argument, which is a union. That means I need to specify which union member to use, and it looks like we want the `@generic` option.
Now, let's break down the actual call:
```
r0 = syz_usb_connect(3, AUTO, &AUTO=@generic={0, &AUTO="12010002000000403b0904a10100000000010902200001010080000904000002ff00ff000705840340000107058802400000", 0, 0, &AUTO=[{0x84, &AUTO="0000aa55"}]}, 0)
```
The first thing to do is ensure the correct union field is assigned. Looks like `@generic` is what we want.
I need to map this to the `vusb_dev_generic` structure:
```
type vusb_dev_generic {
type const[0, int32]
descriptors ptr[in, array[int8]]
bos_descriptor ptr[in, array[int8]]
ep0_responses ptr[in, array[vusb_ep0_response]]
ep_responses ptr[in, array[vusb_ep_response]]
}
```
The `type` field is a `const[0, int32]`. So either `0` or `AUTO` should work, which is being handled in the code above.
The `descriptors` field is a `ptr[in, array[int8]]`. Good, we are using a literal, `&AUTO="1201..."`. That's a valid descriptor setup.
`bos_descriptor` is `ptr[in, array[int8]]`. We're setting that to `0`, which is fine.
`ep0_responses` is `ptr[in, array[vusb_ep0_response]]`. Zeroing it out, also reasonable.
Finally, `ep_responses` is `ptr[in, array[vusb_ep_response]]`. We are using `&AUTO=[{0x84, &AUTO="0000aa55"}]`, which looks like an endpoint response. Good.
I'm feeling confident about this, so I'm going to test the updated call and see how it goes.
|
| 468/2 |
2026/07/30 13:29 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, AUTO, &AUTO=@generic={0, &AUTO="12010002000000403b0904a10100000000010902200001010080000904000002ff00ff000705840340000107058802400000", 0, 0, &AUTO=[{0x84, &AUTO="0000aa55"}]}, 0)
r1 = syz_open_dev$i2c(&AUTO='/dev/i2c-#\x00', 0, 0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, &AUTO=""})
Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 469/2 |
2026/07/30 13:29 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 168413
output: 19
thoughts: 40
Thoughts: Here's my thought process, as if I were considering this myself:
**Examining `syz_usb_connect`**
Okay, hold on a second. I have a hunch that the function signature for `syz_usb_connect` that I'm using in my syzlang descriptions might not be quite right. I need to make absolutely sure. The details matter, and a subtle mismatch could throw off my entire analysis or fuzzing strategy.
Right, so where's the canonical definition? I need to go straight to the source. Let me check the `vusb.txt` file. That's where the most up-to-date and accurate description of the `syz_usb_connect` function should be. I'll compare what I have in my descriptions with what's defined in `vusb.txt` to verify the argument types, the return value, and the overall structure. Gotta get this spot on.
|
| 470/2 |
2026/07/30 13:30 |
tool |
read-description |
0m
Args:
Results: map[Output:# Copyright 2019 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
include <linux/types.h>
include <linux/byteorder/generic.h>
include <uapi/linux/usb/ch9.h>
include <uapi/linux/usb/ch11.h>
include <uapi/linux/usb/midi.h>
include <uapi/linux/usb/audio.h>
include <linux/usb/audio-v2.h>
include <linux/usb/audio-v3.h>
include <uapi/linux/hid.h>
include <linux/hid.h>
include <uapi/linux/usb/cdc.h>
include <uapi/linux/if_ether.h>
include <linux/interrupt.h>
include <linux/usb/cdc_ncm.h>
include <drivers/net/usb/asix.h>
# This is a special fd for USB fuzzing and should only be used with syz_usb_* pseudo-syscalls.
# We don't inherit it from the fd resource, to discourage syzkaller calling raw ioctls on it.
resource fd_usb[int32]: -1
# These are generic pseudo-syscalls for emulating arbitrary USB devices.
# They are mostly targeted to cover the enumeration process.
syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io(fd fd_usb, descs ptr[in, vusb_descriptors], resps ptr[in, vusb_responses]) (timeout[300], remote_cover)
syz_usb_ep_write(fd fd_usb, ep int8, len len[data], data ptr[in, array[int8, 0:256]]) (timeout[300], remote_cover)
syz_usb_ep_read(fd fd_usb, ep int8, len len[data], data buffer[out]) (timeout[300], remote_cover)
syz_usb_disconnect(fd fd_usb) (timeout[300], remote_cover)
usb_device_speed = USB_SPEED_UNKNOWN, USB_SPEED_LOW, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_WIRELESS, USB_SPEED_SUPER, USB_SPEED_SUPER_PLUS
# TODO: consider patching idVendor and idProduct for all class specific descriptions in Go code to cover more drivers.
# TODO: custom syz_usb_ep_write() descriptions for all class specific descriptions.
# TODO: consider adding custom vusb_connect_descriptors definitions to all class specific descriptions.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
type usb_device_descriptor_verbose_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] {
bLength const[USB_DT_DEVICE_SIZE, int8]
bDescriptorType const[USB_DT_DEVICE, int8]
bcdUSB USB
bDeviceClass const[CLASS, int8]
bDeviceSubClass const[SUBCLASS, int8]
bDeviceProtocol const[PROTOCOL, int8]
bMaxPacketSize0 PACKET
idVendor const[VENDOR, int16]
idProduct const[PRODUCT, int16]
bcdDevice const[DEVICE, int16]
iManufacturer const[1, int8]
iProduct const[2, int8]
iSerialNumber const[3, int8]
bNumConfigurations len[configs, int8]
configs CFS
} [packed]
type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[flags[usb_versions, int16], CLASS, SUBCLASS, PROTOCOL, flags[usb_device_max_packet_sizes, int8], VENDOR, PRODUCT, DEVICE, CFS]
type usb_device_descriptor_fixed_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[const[USB, int16], CLASS, SUBCLASS, PROTOCOL, const[PACKET, int8], VENDOR, PRODUCT, DEVICE, CFS]
usb_versions = 0x110, 0x200, 0x201, 0x250, 0x300, 0x310
# https://elixir.bootlin.com/linux/v5.1.7/source/drivers/usb/core/hub.c#L4661
usb_device_max_packet_sizes = 8, 16, 32, 64, 255
type usb_config_descriptor_verbose_t[NUM, IFSNUM, ICONFIG, ATTRS, POWER, EXTRA, IFS] {
bLength const[USB_DT_CONFIG_SIZE, int8]
bDescriptorType const[USB_DT_CONFIG, int8]
wTotalLength len[parent, int16]
bNumInterfaces IFSNUM
bConfigurationValue NUM
iConfiguration ICONFIG
bmAttributes ATTRS
bMaxPower POWER
extra EXTRA
interfaces IFS
} [packed]
type usb_config_descriptor_t[NUM, IFSNUM, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, void, IFS]
type usb_config_descriptor_ifaces_array_t[NUM, IFS] usb_config_descriptor_t[NUM, len[interfaces, int8], IFS]
type usb_config_descriptor_fixed_t[NUM, IFSNUM, ATTRS, POWER, IFS] usb_config_descriptor_verbose_t[const[NUM, int8], const[IFSNUM, int8], const[0, int8], const[ATTRS, int8], const[POWER, int8], void, IFS]
type usb_config_descriptor_extra_t[NUM, IFSNUM, EXTRA, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, EXTRA, IFS]
type usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, IIF, EXTRA, EPS] {
bLength const[USB_DT_INTERFACE_SIZE, int8]
bDescriptorType const[USB_DT_INTERFACE, int8]
bInterfaceNumber IFNUM
bAlternateSetting ALTNUM
bNumEndpoints EPSNUM
bInterfaceClass CLASS
bInterfaceSubClass SUBCLASS
bInterfaceProtocol PROTOCOL
iInterface IIF
extra EXTRA
endpoints EPS
} [packed]
type usb_interface_descriptor_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, int8, EXTRA, EPS]
type usb_interface_descriptor_eps_array_t[IFNUM, ALTNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_t[IFNUM, ALTNUM, len[endpoints, int8], CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS]
type usb_interface_descriptor_fixed_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[const[IFNUM, int8], const[ALTNUM, int8], const[EPSNUM, int8], const[CLASS, int8], const[SUBCLASS, int8], const[PROTOCOL, int8], const[0, int8], EXTRA, EPS]
# TODO: non-audio endpoints have USB_DT_ENDPOINT_SIZE.
type usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, PACKET, INTERVAL, REFRESH, SYNCH, EXTRA] {
bLength const[USB_DT_ENDPOINT_AUDIO_SIZE, int8]
bDescriptorType const[USB_DT_ENDPOINT, int8]
bEndpointAddress ADDR
bmAttributes ATTRS
wMaxPacketSize PACKET
bInterval INTERVAL
bRefresh REFRESH
bSynchAddress SYNCH
extra EXTRA
} [packed]
type usb_endpoint_descriptor_t[ADDR, ATTRS, EXTRA] usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, EXTRA]
type usb_endpoint_descriptor_fixed_t[ADDR, ATTRS, PACKET, INTERVAL, EXTRA] usb_endpoint_descriptor_verbose_t[const[ADDR, int8], const[ATTRS, int8], const[PACKET, int16], const[INTERVAL, int8], const[0, int8], const[0, int8], EXTRA]
# TODO: dummy driver has complex requirements for packet sizes, account for those:
# https://elixir.bootlin.com/linux/v5.3.6/source/drivers/usb/gadget/udc/dummy_hcd.c#L497
usb_endpoint_max_packet_sizes = 8, 16, 32, 64, 512, 1023, 1024
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Generic USB device, configuration, interface and endpoint descriptors.
# We only support one configuration per device.
# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct
# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]]
} [packed]
usb_config_descriptor {
inner usb_config_descriptor_ifaces_array_t[int8, array[usb_interface_descriptor, 1:4]]
} [packed]
usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY
# bInterfaceNumber, bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol
# are patched by Go code, see sys/linux/init_vusb.go.
usb_interface_descriptor {
inner usb_interface_descriptor_eps_array_t[int8, int8, const[0, int8], const[0, int8], const[0, int8], array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
} [packed]
usb_endpoint_descriptor {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], array[usb_endpoint_extra_descriptor, 0:2]]
} [packed]
usb_endpoint_addresses = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, USB_DIR_OUT, USB_DIR_IN
usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK
vusb_connect_descriptors {
qual_len len[qual, int32]
qual ptr[in, usb_qualifier_descriptor]
bos_len len[bos, int32]
bos ptr[in, usb_bos_descriptor]
strs_len len[strs, int32]
strs array[vusb_connect_string_descriptor]
} [packed]
vusb_connect_string_descriptor {
len len[str, int32]
str ptr[in, usb_string_descriptor]
} [packed]
vusb_descriptors {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
string ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
bos ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_BOS, usb_bos_descriptor]]
hub_hs ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_HUB, usb_hub_descriptor_hs]]
hub_ss ptr[in, vusb_descriptor_t[USB_TYPE_CLASS, USB_DT_SS_HUB, usb_hub_descriptor_ss]]
} [packed]
vusb_descriptor_generic {
req_type flags[usb_request_types, int8]
desc_type flags[usb_descriptor_types, int8]
len bytesize[data, int32]
data usb_generic_descriptor
} [packed]
usb_request_types = USB_TYPE_STANDARD, USB_TYPE_CLASS, USB_TYPE_VENDOR
type vusb_descriptor_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# TODO: consider doing lookups based on USB_RECIP values.
vusb_responses {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
get_interface ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
get_configuration ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
# TODO: move these into custom descriptions for hub class when they are added.
hub_USB_REQ_GET_STATUS_hub ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_hub_status]]
hub_USB_REQ_GET_STATUS_port ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_REQ_GET_STATUS, usb_port_status]]
# TODO: move these into custom descriptions for asix driver when they are added.
asix_AX_CMD_READ_MII_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MII_REG, int16]]
asix_AX_CMD_STATMNGSTS_REG ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_STATMNGSTS_REG, int8]]
asix_AX_CMD_READ_EEPROM ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_EEPROM, array[int8, 2]]]
asix_AX_CMD_READ_RX_CTL ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_RX_CTL, int16]]
asix_AX_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_NODE_ID, mac_addr]]
asix_AX88172_CMD_READ_NODE_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX88172_CMD_READ_NODE_ID, mac_addr]]
asix_AX_CMD_READ_PHY_ID ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_PHY_ID, array[int8, 2]]]
asix_AX_CMD_READ_MEDIUM_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MEDIUM_STATUS, int16]]
asix_AX_CMD_READ_MONITOR_MODE ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_MONITOR_MODE, int8]]
asix_AX_CMD_READ_GPIOS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_READ_GPIOS, int8]]
asix_AX_CMD_SW_PHY_STATUS ptr[in, vusb_response_t[USB_TYPE_VENDOR, AX_CMD_SW_PHY_STATUS, int8]]
} [packed]
vusb_response_generic {
type flags[usb_request_types, int8]
req flags[usb_requests, int8]
len bytesize[data, int32]
data array[int8, 0:256]
} [packed]
usb_requests = USB_REQ_GET_STATUS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, USB_REQ_SET_ADDRESS, USB_REQ_GET_DESCRIPTOR, USB_REQ_SET_DESCRIPTOR, USB_REQ_GET_CONFIGURATION, USB_REQ_SET_CONFIGURATION, USB_REQ_GET_INTERFACE, USB_REQ_SET_INTERFACE, USB_REQ_SYNCH_FRAME, USB_REQ_SET_SEL, USB_REQ_SET_ISOCH_DELAY, USB_REQ_SET_ENCRYPTION, USB_REQ_GET_ENCRYPTION, USB_REQ_RPIPE_ABORT, USB_REQ_SET_HANDSHAKE, USB_REQ_RPIPE_RESET, USB_REQ_GET_HANDSHAKE, USB_REQ_SET_CONNECTION, USB_REQ_SET_SECURITY_DATA, USB_REQ_GET_SECURITY_DATA, USB_REQ_SET_WUSB_DATA, USB_REQ_LOOPBACK_DATA_WRITE, USB_REQ_LOOPBACK_DATA_READ, USB_REQ_SET_INTERFACE_DS, USB_REQ_GET_PARTNER_PDO, USB_REQ_GET_BATTERY_STATUS, USB_REQ_SET_PDO, USB_REQ_GET_VDM, USB_REQ_SEND_VDM
type vusb_response_t[CLASS, REQ, DATA] {
type const[CLASS, int8]
req const[REQ, int8]
len bytesize[data, int32]
data DATA
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested by the kernel before the SET_CONFIGURATION request.
# TODO: figure out when is the USB_DT_OTG descriptor used.
# TODO: figure out when is the USB_DT_INTERFACE_ASSOCIATION descriptor used.
# TODO: figure out when is the USB_DT_BOS descriptor used.
type usb_string_descriptor_t[DATA] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_STRING, int8]
data DATA
} [packed]
usb_string_descriptor [
lang_id usb_string_descriptor_t[flags[usb_lang_ids, int16]]
string usb_string_descriptor_t[array[int8, 0:256]]
] [varlen]
usb_lang_ids = 0x436, 0x41c, 0x401, 0x801, 0xc01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001, 0x42b, 0x44d, 0x42c, 0x82c, 0x42d, 0x423, 0x445, 0x402, 0x455, 0x403, 0x404, 0x804, 0xc04, 0x1004, 0x1404, 0x41a, 0x405, 0x406, 0x413, 0x813, 0x409, 0x809, 0xc09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x425, 0x438, 0x429, 0x40b, 0x40c, 0x80c, 0xc0c, 0x100c, 0x140c, 0x180c, 0x437, 0x407, 0x807, 0xc07, 0x1007, 0x1407, 0x408, 0x447, 0x40d, 0x439, 0x40e, 0x40f, 0x421, 0x410, 0x810, 0x411, 0x44b, 0x860, 0x43f, 0x457, 0x412, 0x812, 0x426, 0x427, 0x827, 0x42f, 0x43e, 0x83e, 0x44c, 0x458, 0x44e, 0x861, 0x414, 0x814, 0x448, 0x415, 0x416, 0x816, 0x446, 0x418, 0x419, 0x44f, 0xc1a, 0x81a, 0x459, 0x41b, 0x424, 0x40a, 0x80a, 0xc0a, 0x100a, 0x140a, 0x180a, 0x1c0a, 0x200a, 0x240a, 0x280a, 0x2c0a, 0x300a, 0x340a, 0x380a, 0x3c0a, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a, 0x430, 0x441, 0x41d, 0x81d, 0x449, 0x444, 0x44a, 0x41e, 0x41f, 0x422, 0x420, 0x820, 0x443, 0x843, 0x42a, 0x4ff, 0xf0ff, 0xf4ff, 0xf8ff, 0xfcff
usb_qualifier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_QUALIFIER, int8]
bcdUSB flags[usb_versions, int16]
bDeviceClass int8
bDeviceSubClass int8
bDeviceProtocol int8
bMaxPacketSize0 flags[usb_device_max_packet_sizes, int8]
bNumConfigurations int8
bRESERVED const[0, int8]
} [packed]
usb_bos_descriptor {
bLength const[USB_DT_BOS_SIZE, int8]
bDescriptorType const[USB_DT_BOS, int8]
wTotalLength len[parent, int16]
bNumDeviceCaps len[caps, int8]
caps array[usb_dev_cap, 0:6]
} [packed]
usb_dev_cap [
generic usb_generic_cap_descriptor
wireless usb_wireless_cap_descriptor
ext_cap usb_ext_cap_descriptor
ss_cap usb_ss_cap_descriptor
ss_container_id usb_ss_container_id_descriptor
ssp_cap usb_ssp_cap_descriptor
ptm_cap usb_ptm_cap_descriptor
] [varlen]
usb_generic_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType flags[usb_capability_types, int8]
data array[int8, 0:256]
} [packed]
usb_capability_types = USB_CAP_TYPE_WIRELESS_USB, USB_CAP_TYPE_EXT, USB_SS_CAP_TYPE, USB_SSP_CAP_TYPE, CONTAINER_ID_TYPE, USB_PTM_CAP_TYPE
usb_wireless_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_WIRELESS_USB, int8]
bmAttributes flags[usb_wireless_cap_attributes, int8]
wPHYRates flags[usb_wireless_cap_phyrates, int16]
bmTFITXPowerInfo int8
bmFFITXPowerInfo int8
bmBandGroup int16
bReserved int8
} [packed]
usb_wireless_cap_attributes = USB_WIRELESS_P2P_DRD, USB_WIRELESS_BEACON_MASK, USB_WIRELESS_BEACON_SELF, USB_WIRELESS_BEACON_DIRECTED, USB_WIRELESS_BEACON_NONE
usb_wireless_cap_phyrates = USB_WIRELESS_PHY_53, USB_WIRELESS_PHY_80, USB_WIRELESS_PHY_107, USB_WIRELESS_PHY_160, USB_WIRELESS_PHY_200, USB_WIRELESS_PHY_320, USB_WIRELESS_PHY_400, USB_WIRELESS_PHY_480
usb_ext_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_CAP_TYPE_EXT, int8]
bmAttributes1 flags[usb_ext_cap_attributes, int32:8]
bmAttributes2 int32:4
bmAttributes3 int32:4
bmAttributes4 int32:16
} [packed]
usb_ext_cap_attributes = USB_LPM_SUPPORT, USB_BESL_SUPPORT, USB_BESL_BASELINE_VALID, USB_BESL_DEEP_VALID
usb_ss_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SS_CAP_TYPE, int8]
bmAttributes flags[usb_ss_cap_attributes, int8]
wSpeedSupported flags[usb_ss_cap_speed, int16]
bFunctionalitySupport int8
bU1devExitLat int8
bU2DevExitLat int16
} [packed]
usb_ss_cap_attributes = USB_LTM_SUPPORT
usb_ss_cap_speed = USB_LOW_SPEED_OPERATION, USB_FULL_SPEED_OPERATION, USB_HIGH_SPEED_OPERATION, USB_5GBPS_OPERATION
usb_ss_container_id_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[CONTAINER_ID_TYPE, int8]
bReserved int8
ContainerID array[int8, 16]
} [packed]
usb_ssp_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_SSP_CAP_TYPE, int8]
bReserved int8
bmAttributesSublinkSpeeds len[bmSublinkSpeedAttr, int32:5]
bmAttributesSpeedIDs int32:27
wFunctionalitySupport flags[usb_ssp_cap_funcs, int16]
wReserved int16
bmSublinkSpeedAttr array[flags[usb_ssp_cap_sublink_speeds, int32], 0:6]
} [packed]
usb_ssp_cap_funcs = USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, USB_SSP_MIN_RX_LANE_COUNT, USB_SSP_MIN_TX_LANE_COUNT
usb_ssp_cap_sublink_speeds = USB_SSP_SUBLINK_SPEED_SSID, USB_SSP_SUBLINK_SPEED_LSE, USB_SSP_SUBLINK_SPEED_ST, USB_SSP_SUBLINK_SPEED_RSVD, USB_SSP_SUBLINK_SPEED_LP, USB_SSP_SUBLINK_SPEED_LSM
usb_ptm_cap_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_DEVICE_CAPABILITY, int8]
bDevCapabilityType const[USB_PTM_CAP_TYPE, int8]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Extra USB descriptors that come after an interface or an endpoint descriptor.
# TODO: consider removing class specific descriptors here for described classes.
usb_interface_extra_descriptor [
generic usb_generic_descriptor
hid_hid usb_hid_descriptor_hid
cdc_ecm usb_cdc_header_ecm
cdc_ncm usb_cdc_header_ncm
uac_control uac_control_iface_extra_descriptors
uac_as uac_as_iface_extra_descriptors
] [varlen]
usb_endpoint_extra_descriptor [
generic usb_generic_descriptor
uac_iso uac_iso_endpoint_descriptor
] [varlen]
usb_generic_descriptor {
bLength len[parent, int8]
bDescriptorType flags[usb_descriptor_types, int8]
data array[int8, 0:256]
} [packed]
usb_descriptor_types = USB_DT_DEVICE, USB_DT_CONFIG, USB_DT_STRING, USB_DT_INTERFACE, USB_DT_ENDPOINT, USB_DT_DEVICE_QUALIFIER, USB_DT_OTHER_SPEED_CONFIG, USB_DT_INTERFACE_POWER, USB_DT_OTG, USB_DT_DEBUG, USB_DT_INTERFACE_ASSOCIATION, USB_DT_SECURITY, USB_DT_KEY, USB_DT_ENCRYPTION_TYPE, USB_DT_BOS, USB_DT_DEVICE_CAPABILITY, USB_DT_WIRELESS_ENDPOINT_COMP, USB_DT_WIRE_ADAPTER, USB_DT_RPIPE, USB_DT_CS_RADIO_CONTROL, USB_DT_PIPE_USAGE, USB_DT_SS_ENDPOINT_COMP, USB_DT_SSP_ISOC_ENDPOINT_COMP, HID_DT_HID, HID_DT_REPORT, HID_DT_PHYSICAL
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# USB descriptors requested after the SET_CONFIGURATION request.
usb_hub_descriptor_hs {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
DeviceRemovable array[int8, USB_HUB_PORTS_BITS]
PortPwrCtrlMask array[int8, USB_HUB_PORTS_BITS]
} [packed]
usb_hub_descriptor_ss {
bDescLength len[parent, int8]
bDescriptorType const[USB_DT_SS_HUB, int8]
bNbrPorts int8
wHubCharacteristics flags[usb_hub_characteristics, int16]
bPwrOn2PwrGood int8
bHubContrCurrent int8
bHubHdrDecLat int8
wHubDelay int16
DeviceRemovable int16
} [packed]
define USB_HUB_PORTS_BITS ((USB_MAXCHILDREN + 1 + 7) / 8)
usb_hub_characteristics = HUB_CHAR_LPSM, HUB_CHAR_COMMON_LPSM, HUB_CHAR_INDV_PORT_LPSM, HUB_CHAR_NO_LPSM, HUB_CHAR_COMPOUND, HUB_CHAR_OCPM, HUB_CHAR_COMMON_OCPM, HUB_CHAR_INDV_PORT_OCPM, HUB_CHAR_NO_OCPM, HUB_CHAR_TTTT, HUB_CHAR_PORTIND
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Replies to USB control requests requested after the SET_CONFIGURATION request.
usb_port_status {
wPortStatus flags[usb_port_status_flags, int16]
wPortChange flags[usb_port_change_flags, int16]
dwExtPortStatus array[flags[usb_ext_port_status_flags, int32], 0:1]
} [packed]
usb_port_status_flags = USB_PORT_STAT_CONNECTION, USB_PORT_STAT_ENABLE, USB_PORT_STAT_SUSPEND, USB_PORT_STAT_OVERCURRENT, USB_PORT_STAT_RESET, USB_PORT_STAT_L1, USB_PORT_STAT_POWER, USB_PORT_STAT_LOW_SPEED, USB_PORT_STAT_HIGH_SPEED, USB_PORT_STAT_TEST, USB_PORT_STAT_INDICATOR, USB_PORT_STAT_LINK_STATE, USB_SS_PORT_STAT_POWER, USB_SS_PORT_STAT_SPEED, USB_PORT_STAT_SPEED_5GBPS, USB_SS_PORT_LS_U0, USB_SS_PORT_LS_U1, USB_SS_PORT_LS_U2, USB_SS_PORT_LS_U3, USB_SS_PORT_LS_SS_DISABLED, USB_SS_PORT_LS_RX_DETECT, USB_SS_PORT_LS_SS_INACTIVE, USB_SS_PORT_LS_POLLING, USB_SS_PORT_LS_RECOVERY, USB_SS_PORT_LS_HOT_RESET, USB_SS_PORT_LS_COMP_MOD, USB_SS_PORT_LS_LOOPBACK
usb_port_change_flags = USB_PORT_STAT_C_CONNECTION, USB_PORT_STAT_C_ENABLE, USB_PORT_STAT_C_SUSPEND, USB_PORT_STAT_C_OVERCURRENT, USB_PORT_STAT_C_RESET, USB_PORT_STAT_C_L1, USB_PORT_STAT_C_BH_RESET, USB_PORT_STAT_C_LINK_STATE, USB_PORT_STAT_C_CONFIG_ERROR
usb_ext_port_status_flags = USB_EXT_PORT_STAT_RX_SPEED_ID, USB_EXT_PORT_STAT_TX_SPEED_ID, USB_EXT_PORT_STAT_RX_LANES, USB_EXT_PORT_STAT_TX_LANES
usb_hub_status {
wHubStatus flags[usb_hub_status_flags, int16]
wHubChange flags[usb_hub_change_flags, int16]
} [packed]
usb_hub_status_flags = HUB_STATUS_LOCAL_POWER, HUB_STATUS_OVERCURRENT
usb_hub_change_flags = HUB_CHANGE_LOCAL_POWER, HUB_CHANGE_OVERCURRENT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# HID device class specific descriptions.
# https://www.usb.org/sites/default/files/documents/hid1_11.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/usbhid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/hid.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_hid.c
# Connected HID devices are known to create the following /dev/ files:
# /dev/hidraw#, /dev/usb/hiddev# and /dev/input/event#.
resource fd_usb_hid[fd_usb]
syz_usb_connect$hid(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_hid], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_hid (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$hid(fd fd_usb_hid, descs ptr[in, vusb_descriptors_hid], resps ptr[in, vusb_responses_hid]) (timeout[300], remote_cover)
# idVendor and idProduct are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor_hid {
inner usb_device_descriptor_t[0, 0, 0, 0, 0, 64, array[usb_config_descriptor_hid, 1]]
} [packed]
usb_config_descriptor_hid {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_hid, 1]]
} [packed]
usb_interface_descriptor_hid {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_HID, int8], const[USB_INTERFACE_SUBCLASS_BOOT, int8], flags[usb_hid_protocols, int8], usb_hid_descriptor_hid, usb_endpoint_descriptors_hid]
} [packed]
usb_hid_protocols = USB_INTERFACE_PROTOCOL_KEYBOARD, USB_INTERFACE_PROTOCOL_MOUSE
usb_endpoint_descriptors_hid {
in usb_endpoint_descriptor_hid_in
out array[usb_endpoint_descriptor_hid_out, 0:1]
} [packed]
usb_endpoint_descriptor_hid_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_IN_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_hid_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_OUT_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_HID_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_HID_IN_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_HID_OUT_ADDRESS (2)
vusb_descriptors_hid {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
# For unknown reasons these are requested as USB_TYPE_STANDARD and not as USB_TYPE_CLASS.
# Linux doesn't request HID_DT_HID, but some hosts might do that.
HID_DT_REPORT ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_REPORT, hid_descriptor_report]]
HID_DT_HID ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, HID_DT_HID, usb_hid_descriptor_hid]]
} [packed]
vusb_responses_hid {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
HID_REQ_GET_REPORT ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_REPORT, array[int8, 0:256]]]
HID_REQ_GET_PROTOCOL ptr[in, vusb_response_t[USB_TYPE_CLASS, HID_REQ_GET_PROTOCOL, int8]]
} [packed]
# USB HID specifications allows for multiple report and physical descriptors
# to be present, but I don't see any support for them in the Linux kernel,
# except for a single report descriptor.
usb_hid_descriptor_hid {
bLength len[parent, int8]
bDescriptorType const[HID_DT_HID, int8]
bcdHID int16
bCountryCode int8
bNumDescriptors const[1, int8]
report_desc usb_hid_class_descriptor_report
} [packed]
usb_hid_class_descriptor_report {
bDescriptorType const[HID_DT_REPORT, int8]
wDescriptorLength int16[0:HID_MAX_DESCRIPTOR_SIZE]
} [packed]
# TODO: it's hard to describe the REPORT descriptor structure via syzkaller
# descriptions, so consider generating it in Go code.
# TODO: the length of REPORT descriptor must match the value in HID descriptor.
# TODO: there are vendor specific REPORT descriptor formats (Logitech HID++).
# Linux HID stack doesn't support long items.
hid_descriptor_report {
items array[hid_report_item_short]
} [packed]
type hid_report_item_short_012_t[TYPE, TAGS] {
bSize len[data, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 0:2]
} [packed]
type hid_report_item_short_4_t[TYPE, TAGS] {
bSize const[3, int8:2]
bType const[TYPE, int8:2]
bTag flags[TAGS, int8:4]
data array[int8, 4]
} [packed]
type hid_report_item_short_t[TYPE, TAGS] [
item_012 hid_report_item_short_012_t[TYPE, TAGS]
item_4 hid_report_item_short_4_t[TYPE, TAGS]
] [varlen]
hid_report_item_short [
main hid_report_item_short_t[HID_ITEM_TYPE_MAIN, hid_report_item_main_tags]
global hid_report_item_short_t[HID_ITEM_TYPE_GLOBAL, hid_report_item_global_tags]
local hid_report_item_short_t[HID_ITEM_TYPE_LOCAL, hid_report_item_local_tags]
] [varlen]
hid_report_item_main_tags = HID_MAIN_ITEM_TAG_INPUT, HID_MAIN_ITEM_TAG_OUTPUT, HID_MAIN_ITEM_TAG_FEATURE, HID_MAIN_ITEM_TAG_BEGIN_COLLECTION, HID_MAIN_ITEM_TAG_END_COLLECTION
hid_report_item_global_tags = HID_GLOBAL_ITEM_TAG_USAGE_PAGE, HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM, HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM, HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT, HID_GLOBAL_ITEM_TAG_UNIT, HID_GLOBAL_ITEM_TAG_REPORT_SIZE, HID_GLOBAL_ITEM_TAG_REPORT_ID, HID_GLOBAL_ITEM_TAG_REPORT_COUNT, HID_GLOBAL_ITEM_TAG_PUSH, HID_GLOBAL_ITEM_TAG_POP
hid_report_item_local_tags = HID_LOCAL_ITEM_TAG_USAGE, HID_LOCAL_ITEM_TAG_USAGE_MINIMUM, HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX, HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM, HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM, HID_LOCAL_ITEM_TAG_STRING_INDEX, HID_LOCAL_ITEM_TAG_STRING_MINIMUM, HID_LOCAL_ITEM_TAG_STRING_MAXIMUM, HID_LOCAL_ITEM_TAG_DELIMITER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# PRINTER device class specific descriptions.
# https://www.usb.org/sites/default/files/usbprint11a021811.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/class/usblp.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/printer.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_printer.c
# Connected PRINTER devices are known to create the following /dev/ files:
# /dev/usb/lp#.
# TODO: write descriptions for those.
# drivers/usb/class/usblp.c
define USBLP_REQ_GET_ID 0x00
define USBLP_REQ_GET_STATUS 0x01
define USBLP_REQ_RESET 0x02
define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00
define USBLP_FIRST_PROTOCOL 1
define USBLP_LAST_PROTOCOL 3
resource fd_usb_printer[fd_usb]
syz_usb_connect$printer(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_printer], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_printer (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$printer(fd fd_usb_printer, descs ptr[in, vusb_descriptors_printer], resps ptr[in, vusb_responses_printer]) (timeout[300], remote_cover)
usb_device_descriptor_printer {
inner usb_device_descriptor_t[0, 0, 0, 0x525, 0xa4a8, 64, array[usb_config_descriptor_printer, 1]]
} [packed]
usb_config_descriptor_printer {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_printer, 1]]
} [packed]
usb_interface_descriptor_printer {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_PRINTER, int8], const[1, int8], int8[USBLP_FIRST_PROTOCOL:USBLP_LAST_PROTOCOL], void, usb_endpoint_descriptors_printer]
} [packed]
usb_endpoint_descriptors_printer {
in usb_endpoint_descriptor_printer_out
out array[usb_endpoint_descriptor_printer_in, 0:1]
} [packed]
usb_endpoint_descriptor_printer_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_OUT_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_printer_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_IN_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_PRINTER_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_PRINTER_OUT_ADDRESS (1)
define USB_ENDPOINT_PRINTER_IN_ADDRESS (2 | USB_DIR_IN)
vusb_descriptors_printer {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_printer {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USBLP_REQ_GET_ID ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_ID, usb_printer_get_id_response]]
USBLP_REQ_GET_STATUS ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_GET_STATUS, int8]]
USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST ptr[in, vusb_response_t[USB_TYPE_CLASS, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, int8]]
} [packed]
usb_printer_get_id_response {
length len[id, int16be]
id array[int8, 0:256]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC ECM (Ethernet) device class specific descriptions.
# https://www.usb.org/document-library/class-definitions-communication-devices-12
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ecm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/u_ether.c
# Connected CDC ECM devices are known to create usbN network interfaces.
# TODO: write descriptions for those.
resource fd_usb_cdc_ecm[fd_usb]
syz_usb_connect$cdc_ecm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ecm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ecm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ecm(fd fd_usb_cdc_ecm, descs ptr[in, vusb_descriptors_cdc_ecm], resps ptr[in, vusb_responses_cdc_ecm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ecm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ecm, 1]]
} [packed]
usb_config_descriptor_cdc_ecm {
inner usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_cdc_ecm, 1]]
} [packed]
# Per specification CDC ECM devices have two interfaces (control and data),
# but here we're merging them into one for simplicity since Linux supports that.
usb_interface_descriptor_cdc_ecm {
inner usb_interface_descriptor_t[const[0, int8], int8, int8[2:3], const[USB_CLASS_COMM, int8], const[USB_CDC_SUBCLASS_ETHERNET, int8], const[USB_CDC_PROTO_NONE, int8], usb_cdc_header_ecm, usb_endpoint_descriptors_cdc_ecm]
} [packed]
usb_endpoint_descriptors_cdc_ecm {
notify array[usb_endpoint_descriptor_cdc_ecm_notify, 0:1]
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
usb_endpoint_descriptor_cdc_ecm_notify {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_in {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_IN_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
usb_endpoint_descriptor_cdc_ecm_out {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_OUT_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]
define USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS (1 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_OUT_ADDRESS (3)
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L155
usb_cdc_header_ecm {
union usb_cdc_union_desc_t[0, 0]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
other array[usb_cdc_header_ecm_other, 0:6]
} [packed]
usb_cdc_header_ecm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
ncm usb_cdc_ncm_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
usb_cdc_header_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_HEADER_TYPE, int8]
bcdCDC int16
} [packed]
usb_cdc_call_mgmt_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_CALL_MANAGEMENT_TYPE, int8]
bmCapabilities flags[usb_cdc_call_mgmt_caps, int8]
bDataInterface int8
} [packed]
usb_cdc_call_mgmt_caps = USB_CDC_CALL_MGMT_CAP_CALL_MGMT, USB_CDC_CALL_MGMT_CAP_DATA_INTF
usb_cdc_acm_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ACM_TYPE, int8]
bmCapabilities flags[usb_cdc_acm_caps, int8]
} [packed]
usb_cdc_acm_caps = USB_CDC_COMM_FEATURE, USB_CDC_CAP_LINE, USB_CDC_CAP_BRK, USB_CDC_CAP_NOTIFY
type usb_cdc_union_desc_t[MASTER, SLAVE] {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_UNION_TYPE, int8]
bMasterInterface0 const[MASTER, int8]
bSlaveInterface0 const[SLAVE, int8]
slave_interfaces array[int8, 0:6]
} [packed]
usb_cdc_country_functional_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_COUNTRY_TYPE, int8]
iCountryCodeRelDate int8
wCountyCode0 int16
country_codes array[int16, 0:6]
} [packed]
usb_cdc_network_terminal_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NETWORK_TERMINAL_TYPE, int8]
bEntityId int8
iName int8
bChannelIndex int8
bPhysicalInterface int8
} [packed]
usb_cdc_ether_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_ETHERNET_TYPE, int8]
iMACAddress const[1, int8]
bmEthernetStatistics int32
wMaxSegmentSize int16
wNumberMCFilters int16
bNumberPowerFilters int8
} [packed]
usb_cdc_dmm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_DMM_TYPE, int8]
bcdVersion int16
wMaxCommand int16
} [packed]
usb_cdc_mdlm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_TYPE, int8]
bcdVersion int16
bGUID usb_cdc_ecm_mbm_guid
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L61
usb_cdc_ecm_mbm_guid {
id0 const[0x14f5e048ba817a3, int64]
id1 const[0x2a397ecbffc007a6, int64]
} [packed]
usb_cdc_mdlm_detail_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MDLM_DETAIL_TYPE, int8]
bGuidDescriptorType int8
bDetailData array[int8, 0:256]
} [packed]
usb_cdc_obex_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_OBEX_TYPE, int8]
bcdVersion int16
} [packed]
usb_cdc_ncm_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_NCM_TYPE, int8]
bcdNcmVersion int16
bmNetworkCapabilities flags[usb_cdc_ncm_ncaps, int8]
} [packed]
usb_cdc_ncm_ncaps = USB_CDC_NCM_NCAP_ETH_FILTER, USB_CDC_NCM_NCAP_NET_ADDRESS, USB_CDC_NCM_NCAP_ENCAP_COMMAND, USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE, USB_CDC_NCM_NCAP_CRC_MODE, USB_CDC_NCM_NCAP_NTB_INPUT_SIZE
usb_cdc_mbim_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_TYPE, int8]
bcdMBIMVersion int16
wMaxControlMessage int16
bNumberFilters int8
bMaxFilterSize int8
wMaxSegmentSize int16
bmNetworkCapabilities int8
} [packed]
usb_cdc_mbim_extended_desc {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[USB_CDC_MBIM_EXTENDED_TYPE, int8]
bcdMBIMExtendedVersion int16
bMaxOutstandingCommandMessages int8
wMTU int16
} [packed]
vusb_descriptors_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
usb_cdc_ecm_mac {
# This is a UTF16 encoded string "424242424242".
data0 const[0x3400320034003200, int64be]
data1 const[0x3400320034003200, int64be]
data2 const[0x3400320034003200, int64be]
} [packed]
vusb_responses_cdc_ecm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CDC NCM class specific descriptions.
# CDC NCM is based on CDC ECM, so some of the descriptions are reused.
# https://www.usb.org/document-library/network-control-model-devices-specification-v10-and-errata-and-adopters-agreement
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ncm.c
resource fd_usb_cdc_ncm[fd_usb]
syz_usb_connect$cdc_ncm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ncm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_cdc_ncm (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$cdc_ncm(fd fd_usb_cdc_ncm, descs ptr[in, vusb_descriptors_cdc_ncm], resps ptr[in, vusb_responses_cdc_ncm]) (timeout[300], remote_cover)
usb_device_descriptor_cdc_ncm {
inner usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ncm, 1]]
} [packed]
usb_config_descriptor_cdc_ncm {
inner usb_config_descriptor_t[const[1, int8], const[2, int8], usb_interface_descriptors_cdc_ncm]
} [packed]
usb_interface_descriptors_cdc_ncm {
control usb_interface_descriptor_fixed_t[0, CDC_NCM_COMM_ALTSETTING_NCM, 1, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, usb_cdc_header_ncm, usb_endpoint_descriptor_cdc_ecm_notify]
data_nop usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, void]
data usb_interface_descriptor_fixed_t[1, CDC_NCM_DATA_ALTSETTING_NCM, 2, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, usb_endpoint_descriptors_cdc_ncm_data]
} [packed]
usb_endpoint_descriptors_cdc_ncm_data {
in usb_endpoint_descriptor_cdc_ecm_in
out usb_endpoint_descriptor_cdc_ecm_out
} [packed]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ncm.c#L798
usb_cdc_header_ncm {
union usb_cdc_union_desc_t[0, 1]
header usb_cdc_header_desc
ether usb_cdc_ether_desc
ncm usb_cdc_ncm_desc
other array[usb_cdc_header_ncm_other, 0:6]
} [packed]
usb_cdc_header_ncm_other [
call_mgmt usb_cdc_call_mgmt_descriptor
acm usb_cdc_acm_descriptor
country_functional usb_cdc_country_functional_desc
network_terminal usb_cdc_network_terminal_desc
dmm usb_cdc_dmm_desc
mdlm usb_cdc_mdlm_desc
mdlm_detail usb_cdc_mdlm_detail_desc
obex usb_cdc_obex_desc
mbim usb_cdc_mbim_desc
mbim_extended usb_cdc_mbim_extended_desc
] [varlen]
vusb_descriptors_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/usbnet.c#L147
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor_t[usb_cdc_ecm_mac]]]
} [packed]
vusb_responses_cdc_ncm {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_CDC_GET_NTB_PARAMETERS ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_PARAMETERS, usb_cdc_ncm_ntb_parameters]]
USB_CDC_GET_NTB_INPUT_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_INPUT_SIZE, int32]]
USB_CDC_GET_NTB_FORMAT ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_NTB_FORMAT, int16[0:1]]]
USB_CDC_GET_MAX_DATAGRAM_SIZE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_MAX_DATAGRAM_SIZE, int16]]
USB_CDC_GET_CRC_MODE ptr[in, vusb_response_t[USB_TYPE_CLASS, USB_CDC_GET_CRC_MODE, int16[0:1]]]
} [packed]
usb_cdc_ncm_ntb_parameters {
wLength int16
bmNtbFormatsSupported int16
dwNtbInMaxSize int32
wNdpInDivisor int16
wNdpInPayloadRemainder int16
wNdpInAlignment int16
wPadding1 int16
dwNtbOutMaxSize int32
wNdpOutDivisor int16
wNdpOutPayloadRemainder int16
wNdpOutAlignment int16
wNtbOutMaxDatagrams int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC1 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1_legacy.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
# TODO: find out which /dev/ files are created by connected UAC1 devices and add descriptions for those.
resource fd_usb_uac1[fd_usb]
syz_usb_connect$uac1(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac1], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac1 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac1(fd fd_usb_uac1, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac1 {
inner usb_device_descriptor_t[0, 0, 0, 0x1d6b, 0x101, 64, array[usb_config_descriptor_uac1, 1]]
} [packed]
usb_config_descriptor_uac1 {
inner usb_config_descriptor_t[const[1, int8], const[3, int8], usb_interface_descriptors_uac1]
} [packed]
# TODO: control interface might have and optional interrupt endpoint.
usb_interface_descriptors_uac1 {
inner usb_interface_descriptors_uac1_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac1_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, 0, uac_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC uses IDs to make it possible for terminals and units to refer to each other.
# We don't have a way to describe this, so just use a limited number of ids.
type uac_id int8[1:6]
uac_control_iface_extra_descriptors {
header uac1_ac_header_descriptor
others array[uac_control_iface_extra_descriptor, 0:6]
} [packed]
uac1_ac_header_descriptor {
bLength const[UAC_DT_AC_HEADER_LENGTH, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdADC int16
wTotalLength len[uac_control_iface_extra_descriptors, int16]
bInCollection const[F_AUDIO_NUM_INTERFACES, int8]
# These must match interfaces numbers.
baInterfaceNr0 const[1, int8]
baInterfaceNr1 const[2, int8]
} [packed]
uac_control_iface_extra_descriptor [
input_terminal uac_input_terminal_descriptor
output_terminal uac1_output_terminal_descriptor
mixer_unit uac_mixer_unit_descriptor
selector_unit uac_selector_unit_descriptor
feature_unit uac_feature_unit_descriptor
processing_unit uac_processing_unit_descriptor
extension_unit uac_extension_unit_descriptor
] [varlen]
define F_AUDIO_NUM_INTERFACES 2
define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
uac_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bNrChannels int8
wChannelConfig int16
iChannelNames int8
iTerminal int8
} [packed]
# The following list contains input terminal types and inout terminal types.
uac_input_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_INPUT_TERMINAL_UNDEFINED, UAC_INPUT_TERMINAL_MICROPHONE, UAC_INPUT_TERMINAL_DESKTOP_MICROPHONE, UAC_INPUT_TERMINAL_PERSONAL_MICROPHONE, UAC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE, UAC_INPUT_TERMINAL_MICROPHONE_ARRAY, UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
# The following list contains output terminal types and inout terminal types.
uac_output_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_OUTPUT_TERMINAL_UNDEFINED, UAC_OUTPUT_TERMINAL_SPEAKER, UAC_OUTPUT_TERMINAL_HEADPHONES, UAC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO, UAC_OUTPUT_TERMINAL_DESKTOP_SPEAKER, UAC_OUTPUT_TERMINAL_ROOM_SPEAKER, UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER, UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER, UAC_BIDIR_TERMINAL_UNDEFINED, UAC_BIDIR_TERMINAL_HANDSET, UAC_BIDIR_TERMINAL_HEADSET, UAC_BIDIR_TERMINAL_SPEAKER_PHONE, UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING, UAC_BIDIR_TERMINAL_ECHO_CANCELING
uac1_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
iTerminal int8
} [packed]
uac_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_selector_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_SELECTOR_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bControlSize len[bmaControls, int8]
bmaControls array[flags[uac_feature_unit_controls, int16], 1:6]
iFeature int8
} [packed]
uac_feature_unit_controls = UAC_FU_MUTE, UAC_FU_VOLUME, UAC_FU_BASS, UAC_FU_MID, UAC_FU_TREBLE, UAC_FU_GRAPHIC_EQUALIZER, UAC_FU_AUTOMATIC_GAIN, UAC_FU_DELAY, UAC_FU_BASS_BOOST, UAC_FU_LOUDNESS
uac_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_PROCESSING_UNIT, int8]
bUnitID uac_id
wProcessType flags[uac_processing_unit_types, int16]
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac_processing_unit_types = UAC_PROCESS_UNDEFINED, UAC_PROCESS_UP_DOWNMIX, UAC_PROCESS_DOLBY_PROLOGIC, UAC_PROCESS_STEREO_EXTENDER, UAC_PROCESS_REVERB, UAC_PROCESS_CHORUS, UAC_PROCESS_DYN_RANGE_COMP
uac_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC1_EXTENSION_UNIT, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_iface_extra_descriptors {
others array[uac_as_iface_extra_descriptor, 0:6]
} [packed]
uac_as_iface_extra_descriptor [
as_header uac1_as_header_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
format_type_i_ext uac_format_type_i_ext_descriptor
] [varlen]
uac1_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bDelay int8
wFormatTag flags[uac_format_tags, int16]
} [packed]
uac_format_tags = UAC_FORMAT_TYPE_I_UNDEFINED, UAC_FORMAT_TYPE_I_PCM, UAC_FORMAT_TYPE_I_PCM8, UAC_FORMAT_TYPE_I_IEEE_FLOAT, UAC_FORMAT_TYPE_I_ALAW, UAC_FORMAT_TYPE_I_MULAW, UAC_FORMAT_TYPE_II_MPEG, UAC_FORMAT_TYPE_II_AC3
uac_usb_format_types_i = UAC_FORMAT_TYPE_I, UAC_FORMAT_TYPE_II, UAC_FORMAT_TYPE_III, UAC_FORMAT_TYPE_UNDEFINED
uac_format_type_i_continuous_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tLowerSamFreq array[int8, 0:3]
tUpperSamFreq array[int8, 0:3]
} [packed]
uac_format_type_i_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bNrChannels int8
bSubframeSize int8[1:4]
bBitResolution int8
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
uac_format_type_ii_discrete_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bSamFreqType int8
tSamFreq array[int8, 0:9]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
uac_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]
define USB_ENDPOINT_UAC1_AS_OUT_ADDRESS (1 | USB_DIR_OUT)
define USB_ENDPOINT_UAC1_AS_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_UAC1_AS_ATTRIBUTES (USB_ENDPOINT_SYNC_ADAPTIVE | USB_ENDPOINT_XFER_ISOC)
uac_iso_ep_attributes = USB_ENDPOINT_SYNCTYPE, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC
uac_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC_EP_GENERAL, int8]
bmAttributes flags[uac_iso_ep_attributes, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
vusb_descriptors_uac1 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_uac1 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
audio_UAC_GET_CUR ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_CUR, array[int8, 1:3]]]
audio_UAC_GET_MIN ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MIN, array[int8, 1:3]]]
audio_UAC_GET_MAX ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MAX, array[int8, 1:3]]]
audio_UAC_GET_RES ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_RES, array[int8, 1:4]]]
audio_UAC_GET_MEM ptr[in, vusb_response_t[USB_TYPE_CLASS, UAC_GET_MEM, array[int8, 3]]]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC2 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac2.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac2[fd_usb]
syz_usb_connect$uac2(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac2], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac2 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac2(fd fd_usb_uac2, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac2 {
inner usb_device_descriptor_t[0, 0, 0, 0x41e, 0x3000, 64, array[usb_config_descriptor_uac2, 1]]
} [packed]
usb_config_descriptor_uac2 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac2_interface_assoc_descriptor, usb_interface_descriptors_uac2]
} [packed]
uac2_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[audio_function_category_types, int8]
bFunctionProtocol const[UAC_VERSION_2, int8]
iFunction int8
} [packed]
audio_function_category_types = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER
usb_interface_descriptors_uac2 {
inner usb_interface_descriptors_uac2_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac2_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_2, uac2_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_2, uac2_as_iface_extra_descriptors, uac2_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptors {
header uac2_ac_header_descriptor
others array[uac2_control_iface_extra_descriptor, 0:6]
} [packed]
uac2_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bcdADC int16
bCategory flags[uac2_feature_unit_controls, int8]
wTotalLength len[uac2_control_iface_extra_descriptors, int16]
bmControls int8
} [packed]
uac2_feature_unit_controls = UAC2_FUNCTION_SUBCLASS_UNDEFINED, UAC2_FUNCTION_DESKTOP_SPEAKER, UAC2_FUNCTION_HOME_THEATER, UAC2_FUNCTION_MICROPHONE, UAC2_FUNCTION_HEADSET, UAC2_FUNCTION_TELEPHONE, UAC2_FUNCTION_CONVERTER, UAC2_FUNCTION_SOUND_RECORDER, UAC2_FUNCTION_IO_BOX, UAC2_FUNCTION_MUSICAL_INSTRUMENT, UAC2_FUNCTION_PRO_AUDIO, UAC2_FUNCTION_AUDIO_VIDEO, UAC2_FUNCTION_CONTROL_PANEL, UAC2_FUNCTION_OTHER, uac_feature_unit_controls
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_as_iface_extra_descriptors {
others array[uac2_as_iface_extra_descriptor, 0:6]
} [packed]
uac2_as_iface_extra_descriptor [
as_header uac2_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
uac2_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int8
bFormatType flags[uac_usb_format_types_i, int8]
bmFormats flags[uac_format_tags, int32]
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
} [packed]
b_sub_slot_sizes = 1, 2, 3, 4
uac2_format_type_i_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize flags[b_sub_slot_sizes, int8]
bBitResolution int8
} [packed]
uac2_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac_format_type_ii_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_II, int8]
wMaxBitRate int16
wSamplesPerFrame int16
bHeaderLength int8
bSideBandProtocol int8
} [packed]
uac_format_type_i_ext_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_FORMAT_TYPE, int8]
bFormatType const[UAC_FORMAT_TYPE_I, int8]
bSubslotSize int8
bBitResolution int8
bHeaderLength int8
bControlSize int8
bSideBandProtocol int8
} [packed]
uac2_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac2_iso_endpoint_descriptor]
} [packed]
uac2_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubtype const[UAC_EP_GENERAL, int8]
bmAttributes flags[csep_bm_attributes, int8]
bmControls flags[csep_bm_controls, int8]
bLockDelayUnits int8
wLockDelay int16
} [packed]
csep_bm_attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, UAC_EP_CS_ATTR_PITCH_CONTROL, UAC_EP_CS_ATTR_FILL_MAX
csep_bm_controls = UAC2_CONTROL_PITCH, UAC2_CONTROL_DATA_OVERRUN, UAC2_CONTROL_DATA_UNDERRUN
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac2_control_iface_extra_descriptor [
input_terminal uac2_input_terminal_descriptor
output_terminal uac2_output_terminal_descriptor
mixer_unit uac2_mixer_unit_descriptor
selector_unit uac2_clock_selector_descriptor
feature_unit uac2_feature_unit_descriptor
processing_unit uac2_processing_unit_descriptor
extension_unit uac2_extension_unit_descriptor
effect_unit uac2_effect_unit_descriptor
sample_rate uac2_sample_rate_descriptor
source_unit uac2_clock_source_descriptor
multiply_unit uac2_clock_multiplier_descriptor
] [varlen]
uac2_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bNrChannels int8
bmChannelConfig int32
iChannelNames int8
bmControls int8
iTerminal int8
} [packed]
uac2_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal int8
bSourceID uac_id
bCSourceID int8
bmControls int16
iTerminal int8
} [packed]
uac2_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Figure out if bmControls and iClockSelector should be a part of this structure.
uac2_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
# TODO: Verify coverage.
uac2_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_PROCESSING_UNIT_V2, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_processing_unit_types = UAC2_PROCESS_UNDEFINED, UAC2_PROCESS_UP_DOWNMIX, UAC2_PROCESS_DOLBY_PROLOCIC, UAC2_PROCESS_STEREO_EXTENDER
uac2_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_EXTENSION_UNIT_V2, int8]
bUnitID uac_id
wProcessType int16
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
# TODO: Verify coverage.
uac2_effect_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_EFFECT_UNIT, int8]
bUnitID uac_id
wEffectType flags[uac2_effect_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_effect_unit_types = UAC2_EFFECT_UNDEFINED, UAC2_EFFECT_PARAM_EQ, UAC2_EFFECT_REVERB, UAC2_EFFECT_MOD_DELAY, UAC2_EFFECT_DYN_RANGE_COMP
uac2_sample_rate_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC2_SAMPLE_RATE_CONVERTER, int8]
bUnitID uac_id
wProcessType flags[uac2_processing_unit_types, int16]
bSourceID uac_id
bmaControls array[flags[uac2_processing_unit_types, int16], 1:6]
} [packed]
uac2_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac2_feature_unit_controls, int16], 1:6]
} [packed]
uac2_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac2_clock_bmattribute_types, int8]
bmControls int8
bAssocTerminal int8
iClockSource flags[uac2_clock_source_types, int8]
} [packed]
uac2_clock_bmattribute_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_source_types = UAC_CLOCK_SOURCE_TYPE_EXT, UAC_CLOCK_SOURCE_TYPE_INT_FIXED, UAC_CLOCK_SOURCE_TYPE_INT_VAR, UAC_CLOCK_SOURCE_TYPE_INT_PROG, UAC_CLOCK_SOURCE_SYNCED_TO_SOF
uac2_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC2_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int8
iClockMultiplier int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# UAC3 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac3.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h
resource fd_usb_uac3[fd_usb]
syz_usb_connect$uac3(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac3], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb_uac3 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$uac3(fd fd_usb_uac3, descs ptr[in, vusb_descriptors_uac1], resps ptr[in, vusb_responses_uac1]) (timeout[300], remote_cover)
usb_device_descriptor_uac3 {
inner usb_device_descriptor_t[0, 0, 0, 0x582, 0x582, 64, array[usb_config_descriptor_uac3, 1]]
} [packed]
usb_config_descriptor_uac3 {
inner usb_config_descriptor_extra_t[const[1, int8], const[3, int8], uac3_interface_assoc_descriptor, usb_interface_descriptors_uac3]
} [packed]
uac3_interface_assoc_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_INTERFACE_ASSOCIATION, int8]
bFirstInterface int8[0:2]
bInterfaceCount int8[0:2]
bFunctionClass const[USB_CLASS_AUDIO, int8]
bFunctionSubClass flags[uac3_all_subclasses, int8]
bFunctionProtocol const[UAC_VERSION_3, int8]
iFunction int8
} [packed]
usb_interface_descriptors_uac3 {
inner usb_interface_descriptors_uac3_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_uac3_inner {
control usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, UAC_VERSION_3, uac3_control_iface_extra_descriptors, void]
as_out_alt_0 usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_out_alt_1 usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_out_endpoint_descriptor]
as_in_alt_0 usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, void, void]
as_in_alt_1 usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, UAC_VERSION_3, uac3_as_iface_extra_descriptors, uac3_as_in_endpoint_descriptor]
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptors {
header uac3_ac_header_descriptor
others array[uac3_control_iface_extra_descriptor, 0:6]
} [packed]
uac3_ac_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MS_HEADER, int8]
bCategory flags[uac3_feature_unit_controls, int8]
wTotalLength len[uac3_control_iface_extra_descriptors, int16]
bmControls int32
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_as_iface_extra_descriptors {
others array[uac3_as_iface_extra_descriptor, 0:6]
} [packed]
uac3_as_iface_extra_descriptor [
as_header uac3_as_header_descriptor
format_type_i_descriptor uac2_format_type_i_descriptor
format_type_i_continuous uac_format_type_i_continuous_descriptor
format_type_i_discrete uac_format_type_i_discrete_descriptor
format_type_ii_discrete uac_format_type_ii_discrete_descriptor
format_type_i_ext uac2_format_type_i_ext_descriptor
format_type_ii_ext uac_format_type_ii_ext_descriptor
] [varlen]
# TODO: Figure out how wClusterDescrID is used in the kernel.
uac3_as_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_AS_GENERAL, int8]
bTerminalLink int8
bmControls int32
wClusterDescrID int16
bmFormats flags[uac_format_tags, int64]
bSubslotSize int8
bBitResolution int8
bmAuxProtocols int16
bControlSize int8
} [packed]
uac3_as_out_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_as_in_endpoint_descriptor {
inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
} [packed]
uac3_iso_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[UAC3_CS_ENDPOINT, int8]
bmControls int32
bLockDelayUnits int8
wLockDelay int16
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
uac3_control_iface_extra_descriptor [
input_terminal uac3_input_terminal_descriptor
output_terminal uac3_output_terminal_descriptor
mixer_unit uac3_mixer_unit_descriptor
selector_unit uac3_clock_selector_descriptor
source_unit uac3_clock_source_descriptor
multiply_unit uac3_clock_multiplier_descriptor
feature_unit uac3_feature_unit_descriptor
processing_unit uac3_processing_unit_descriptor
extension_unit uac3_extension_unit_descriptor
power_domain uac3_power_domain_descriptor
cluster_info_segment uac3_cluster_information_segment_descriptor
# Only cluster information segment is currently used in the kernel.See: sound/usb/stream.c
# cluster_segment uac3_cluster_segment_descriptor
# cluster_end_segment uac3_cluster_end_segment_descriptor
# The following units are not yet supported by the kernel.
# See audio_validators[] in sound/usb/validate.c:
# effect_unit uac3_effect_unit_descriptor
# sample_rate uac3_sample_rate_descriptor
# connectors_unit uac3_connectors_unit_descriptor
# extended_term_unit uac3_extended_terminal_unit
] [varlen]
uac3_input_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_INPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_input_terminal_types, int16]
bAssocTerminal uac_id
bCSourceID int8
bmControls int32
wClusterDescrID int16
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_output_terminal_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC_OUTPUT_TERMINAL, int8]
bTerminalID uac_id
wTerminalType flags[uac_output_terminal_types, int16]
bAssocTerminal uac_id
bSourceID uac_id
bCSourceID int8
bmControls int32
wExTerminalDescrID int16
wConnectorsDescrID int16
wTerminalDescrStr int16
} [packed]
uac3_mixer_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_MIXER_UNIT, int8]
bUnitID uac_id
bNrInPins int8
baSourceID array[int8, 0:6]
} [packed]
uac3_clock_selector_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SELECTOR, int8]
bClockID int8
bNrInPins len[baCSourceID, int8]
baCSourceID array[int8, 0:8]
} [packed]
uac3_clock_source_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_SOURCE, int8]
bClockID int8
bmAttributes flags[uac3_clock_bmattribute_types, int8]
bmControls int32
bReferenceTerminal int8
wClockSourceStr int16
} [packed]
uac3_clock_bmattribute_types = UAC3_CLOCK_SOURCE_TYPE_EXT, UAC3_CLOCK_SOURCE_TYPE_INT, UAC3_CLOCK_SOURCE_ASYNC, UAC3_CLOCK_SOURCE_SYNCED_TO_SOF
uac3_clock_multiplier_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_CLOCK_MULTIPLIER, int8]
bClockID int8
bCSourceID int8
bmControls int32
wCMultiplierDescrStr int16
} [packed]
uac3_feature_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_FEATURE_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_feature_unit_controls, int32], 1:6]
} [packed]
uac3_processing_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_PROCESSING_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_processing_unit_types = UAC3_PROCESS_UNDEFINED, UAC3_PROCESS_UP_DOWNMIX, UAC3_PROCESS_STEREO_EXTENDER, UAC3_PROCESS_MULTI_FUNCTION
uac3_extension_unit_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubtype const[UAC3_EXTENSION_UNIT, int8]
bUnitID uac_id
bSourceID uac_id
bmaControls array[flags[uac3_processing_unit_types, int32], 1:6]
} [packed]
uac3_power_domain_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC3_POWER_DOMAIN, int8]
bPowerDomainID int8
waRecoveryTime1 int16
waRecoveryTime2 int16
bNrEntities int8
baEntityID array[int8, 0:8]
} [packed]
uac3_cluster_information_segment_descriptor {
bLength len[parent, int16]
bSegmentType const[UAC3_CHANNEL_INFORMATION, int8]
bChPurpose flags[uac3_cluster_channel_purposes, int8]
bChRelationship flags[uac3_cluster_channel_relationships, int8]
bChGroupID int8
} [packed]
uac3_cluster_channel_purposes = UAC3_PURPOSE_UNDEFINED, UAC3_PURPOSE_GENERIC_AUDIO, UAC3_PURPOSE_VOICE, UAC3_PURPOSE_SPEECH, UAC3_PURPOSE_AMBIENT, UAC3_PURPOSE_REFERENCE, UAC3_PURPOSE_ULTRASONIC, UAC3_PURPOSE_VIBROKINETIC, UAC3_PURPOSE_NON_AUDIO
uac3_cluster_channel_relationships = UAC3_CH_RELATIONSHIP_UNDEFINED, UAC3_CH_MONO, UAC3_CH_LEFT, UAC3_CH_RIGHT, UAC3_CH_ARRAY, UAC3_CH_PATTERN_X, UAC3_CH_PATTERN_Y, UAC3_CH_PATTERN_A, UAC3_CH_PATTERN_B, UAC3_CH_PATTERN_M, UAC3_CH_PATTERN_S, UAC3_CH_FRONT_LEFT, UAC3_CH_FRONT_RIGHT, UAC3_CH_FRONT_CENTER, UAC3_CH_FRONT_LEFT_OF_CENTER, UAC3_CH_FRONT_RIGHT_OF_CENTER, UAC3_CH_FRONT_WIDE_LEFT, UAC3_CH_FRONT_WIDE_RIGHT, UAC3_CH_SIDE_LEFT, UAC3_CH_SIDE_RIGHT, UAC3_CH_SURROUND_ARRAY_LEFT, UAC3_CH_SURROUND_ARRAY_RIGHT, UAC3_CH_BACK_LEFT, UAC3_CH_BACK_RIGHT, UAC3_CH_BACK_CENTER, UAC3_CH_BACK_LEFT_OF_CENTER, UAC3_CH_BACK_RIGHT_OF_CENTER, UAC3_CH_BACK_WIDE_LEFT, UAC3_CH_BACK_WIDE_RIGHT, UAC3_CH_TOP_CENTER, UAC3_CH_TOP_FRONT_LEFT, UAC3_CH_TOP_FRONT_RIGHT, UAC3_CH_TOP_FRONT_CENTER, UAC3_CH_TOP_FRONT_LOC, UAC3_CH_TOP_FRONT_ROC, UAC3_CH_TOP_FRONT_WIDE_LEFT, UAC3_CH_TOP_FRONT_WIDE_RIGHT, UAC3_CH_TOP_SIDE_LEFT, UAC3_CH_TOP_SIDE_RIGHT, UAC3_CH_TOP_SURR_ARRAY_LEFT, UAC3_CH_TOP_SURR_ARRAY_RIGHT, UAC3_CH_TOP_BACK_LEFT, UAC3_CH_TOP_BACK_RIGHT, UAC3_CH_TOP_BACK_CENTER, UAC3_CH_TOP_BACK_LOC, UAC3_CH_TOP_BACK_ROC, UAC3_CH_TOP_BACK_WIDE_LEFT, UAC3_CH_TOP_BACK_WIDE_RIGHT, UAC3_CH_BOTTOM_CENTER, UAC3_CH_BOTTOM_FRONT_LEFT, UAC3_CH_BOTTOM_FRONT_RIGHT, UAC3_CH_BOTTOM_FRONT_CENTER, UAC3_CH_BOTTOM_FRONT_LOC, UAC3_CH_BOTTOM_FRONT_ROC, UAC3_CH_BOTTOM_FRONT_WIDE_LEFT, UAC3_CH_BOTTOM_FRONT_WIDE_RIGHT, UAC3_CH_BOTTOM_SIDE_LEFT, UAC3_CH_BOTTOM_SIDE_RIGHT, UAC3_CH_BOTTOM_SURR_ARRAY_LEFT, UAC3_CH_BOTTOM_SURR_ARRAY_RIGHT, UAC3_CH_BOTTOM_BACK_LEFT, UAC3_CH_BOTTOM_BACK_RIGHT, UAC3_CH_BOTTOM_BACK_CENTER, UAC3_CH_BOTTOM_BACK_LOC, UAC3_CH_BOTTOM_BACK_ROC, UAC3_CH_BOTTOM_BACK_WIDE_LEFT, UAC3_CH_BOTTOM_BACK_WIDE_RIGHT, UAC3_CH_LOW_FREQUENCY_EFFECTS, UAC3_CH_LFE_LEFT, UAC3_CH_LFE_RIGHT, UAC3_CH_HEADPHONE_LEFT, UAC3_CH_HEADPHONE_RIGHT
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# This list consists of uac3_func_subclasses + uac3_badd_classes.
uac3_all_subclasses = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0, UAC3_FUNCTION_SUBCLASS_GENERIC_IO, UAC3_FUNCTION_SUBCLASS_HEADPHONE, UAC3_FUNCTION_SUBCLASS_SPEAKER, UAC3_FUNCTION_SUBCLASS_MICROPHONE, UAC3_FUNCTION_SUBCLASS_HEADSET, UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE
uac3_feature_unit_controls = UAC3_FUNCTION_SUBCLASS_UNDEFINED, UAC3_FUNCTION_DESKTOP_SPEAKER, UAC3_FUNCTION_HOME_THEATER, UAC3_FUNCTION_MICROPHONE, UAC3_FUNCTION_HEADSET, UAC3_FUNCTION_TELEPHONE, UAC3_FUNCTION_CONVERTER, UAC3_FUNCTION_SOUND_RECORDER, UAC3_FUNCTION_IO_BOX, UAC3_FUNCTION_MUSICAL_INSTRUMENT, UAC3_FUNCTION_PRO_AUDIO, UAC3_FUNCTION_AUDIO_VIDEO, UAC3_FUNCTION_CONTROL_PANEL, UAC3_FUNCTION_HEADPHONE, UAC3_FUNCTION_GENERIC_SPEAKER, UAC3_FUNCTION_HEADSET_ADAPTER, UAC3_FUNCTION_SPEAKERPHONE, UAC3_FUNCTION_OTHER
# TODO: Support uac3 badd profiles. See sound/usb/mixer.c: snd_usb_mixer_controls_badd()
# uac3_badd_endpoint_descriptor {
# inner usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac3_iso_endpoint_descriptor]
# } [packed]
#uac3_badd_maxsizes = UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16,UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24,UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# MIDI device class specific descriptions.
# https://www.usb.org/sites/default/files/midi10.pdf
# https://elixir.bootlin.com/linux/latest/source/sound/usb/midi.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_midi.c
syz_usb_connect$midi(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_midi], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000], remote_cover)
usb_device_descriptor_midi {
inner usb_device_descriptor_t[0, 0, 0, 0x1430, 0x474b, 64, array[usb_config_descriptor_midi, 1]]
} [packed]
usb_config_descriptor_midi {
inner usb_config_descriptor_t[const[1, int8], const[1, int8], usb_interface_descriptors_midi]
} [packed]
usb_interface_descriptors_midi {
inner usb_interface_descriptors_midi_inner
} [packed]
# Define folded-in structure to match layout expected by USB ID patching code.
usb_interface_descriptors_midi_inner {
control usb_interface_descriptor_eps_array_t[const[0, int8], const[0, int8], const[USB_CLASS_AUDIO, int8], const[USB_SUBCLASS_MIDISTREAMING, int8], flags[uac_version_types, int8], array[usb_midi_iface_extra], array[usb_endpoint_descriptor_midi, 0:8]]
} [packed]
usb_endpoint_descriptor_midi {
inner usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], usb_ms_endpoint_descriptor]
} [packed]
midi_jack_type = USB_MS_EMBEDDED, USB_MS_EXTERNAL
uac_version_types = UAC_VERSION_1, UAC_VERSION_2, UAC_VERSION_3
usb_ms_endpoint_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_ENDPOINT, int8]
bDescriptorSubType const[USB_MS_GENERAL, int8]
bNumEmbMIDIJack len[baAssocJackID, int8]
baAssocJackID array[int8, 0:16]
} [packed]
usb_midi_iface_extra [
ms_header usb_ms_header_descriptor
midi_in_jack usb_midi_in_jack_descriptor
midi_out_jack usb_midi_out_jack_descriptor
] [varlen]
usb_ms_header_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_HEADER, int8]
bcdMSC int16
wTotalLength len[parent, int16]
} [packed]
usb_midi_in_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_IN_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
iJack int8
} [packed]
usb_midi_out_jack_descriptor {
bLength len[parent, int8]
bDescriptorType const[USB_DT_CS_INTERFACE, int8]
bDescriptorSubType const[UAC_MIDI_OUT_JACK, int8]
bJackType flags[midi_jack_type, int8]
bJackID int8
bNrInputPins len[pins, int8]
pins array[usb_midi_source_pin]
iJack int8
} [packed]
usb_midi_source_pin {
baSourceID int8
baSourcePin int8
} [packed]
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# ath9k driver specific descriptions.
include <drivers/net/wireless/ath/ath9k/htc_hst.h>
include <drivers/net/wireless/ath/ath9k/hif_usb.h>
define USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS (1)
define USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS (2 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_IN_ADDRESS (3 | USB_DIR_IN)
define USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS (4)
define USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS (5)
define USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS (6)
resource fd_usb_ath9k[fd_usb]
syz_usb_connect_ath9k(speed const[USB_SPEED_HIGH], dev_len len[dev], dev ptr[in, usb_device_descriptor_ath9k], conn_descs const[0]) fd_usb_ath9k (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_ep_write$ath9k_ep1(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS], len bytesize[data], data ptr[in, ath9k_bulk_frame]) (timeout[300], remote_cover)
syz_usb_ep_write$ath9k_ep2(fd fd_usb_ath9k, ep const[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS], len bytesize[data], data ptr[in, htc_frame]) (timeout[300], remote_cover)
usb_device_descriptor_ath9k {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xcf3, 0x9271, 0x108, array[usb_config_descriptor_ath9k, 1]]
} [packed]
usb_config_descriptor_ath9k {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_ath9k]
} [packed]
usb_interface_descriptor_ath9k {
iface usb_interface_descriptor_fixed_t[0, 0, 6, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_ath9k]
} [packed]
usb_endpoint_descriptors_ath9k {
bulk_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_OUT_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_IN_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_IN_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
int_out usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_INT_OUT_ADDRESS, USB_ENDPOINT_ATH9K_INT_ATTRIBUTES, 64, 1, void]
bulk_extra1 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA1_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
bulk_extra2 usb_endpoint_descriptor_fixed_t[USB_ENDPOINT_ATH9K_BULK_EXTRA2_ADDRESS, USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES, 512, 0, void]
} [packed]
define USB_ENDPOINT_ATH9K_BULK_ATTRIBUTES (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_ATH9K_INT_ATTRIBUTES (USB_ENDPOINT_XFER_INT)
ath9k_bulk_frame {
packets array[ath9k_bulk_packet]
} [packed]
ath9k_bulk_packet {
pkt_len len[data, int16]
pkt_tag const[ATH_USB_RX_STREAM_MODE_TAG, int16]
data array[int8]
} [packed, align[4]]
htc_frame [
ready htc_ready_frame
conn_svc_rsp htc_conn_svc_rsp_frame
generic htc_generic_frame
] [varlen]
# This is actually wrong, as the driver is buggy and doesn't skip the header
# before processing the frame payload, but let's leave it like thise for now.
htc_ready_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_ready_msg
} [packed]
htc_ready_msg {
message_id const[HTC_MSG_READY_ID, int16be]
credits int16be
credit_size int16be
max_endpoints int8
pad int8
} [packed]
htc_conn_svc_rsp_frame {
endpoint_id const[0, int8]
flags const[0, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload htc_conn_svc_rspmsg
} [packed]
htc_conn_svc_rspmsg {
message_id const[HTC_MSG_CONNECT_SERVICE_RESPONSE_ID, int16be]
service_id flags[htc_svcs, int16be]
status const[HTC_SERVICE_SUCCESS, int8]
endpoint_id int8
max_msg_len int16be
svc_meta_len int8
pad int8
} [packed]
htc_svcs = HTC_CTRL_RSVD_SVC, HTC_LOOPBACK_RSVD_SVC, WMI_CONTROL_SVC, WMI_BEACON_SVC, WMI_CAB_SVC, WMI_UAPSD_SVC, WMI_MGMT_SVC, WMI_DATA_VO_SVC, WMI_DATA_VI_SVC, WMI_DATA_BE_SVC, WMI_DATA_BE_SVC
htc_generic_frame {
endpoint_id int8[0:8]
flags flags[htc_frame_flags, int8]
payload_len len[payload, int16be]
control array[int8, 4]
payload array[int8, 0:256]
} [packed]
htc_frame_flags = HTC_FLAGS_RECV_TRAILER
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Assorted driver-specific descriptions of generic syz_* calls' variants.
# Generic calls such as syz_usb_connect() and syz_usb_control_io() should be enough
# (in theory) to emulate a proper device and finish driver probes without a hitch.
# However, there are cases when syzkaller fails to come up with correct inputs to achieve it.
# Use fixed descriptors to quickly pass through probe() to access select drivers' post-probe functionality.
# It is important to note that, one way or another, drivers in question require multiple control requests
# between a driver and a device processed during probe(). Descriptions below do not deal with specific
# CTRL requests as such (except for basic information included in vusb_responses_XXX). Instead, rely on
# seeds, created both manually and with syzkaller's help. For examples, see sys/linux/test/vusb_XXX.
# Common constants for endpoint descriptors.
define USB_ENDPOINT_BULK_ATTR (USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_INT_ATTR (USB_ENDPOINT_XFER_INT)
define USB_FIXED_ENDPOINT_BULK_IN_ADDR (1 | USB_DIR_IN)
define USB_FIXED_ENDPOINT_BULK_OUT_ADDR (2)
define USB_FIXED_ENDPOINT_INT_IN_ADDR (3 | USB_DIR_IN)
define USB_RECIP_DEVICE 0x00
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# rtl8150 driver specific descriptions.
resource fd_usb_rtl8150[fd_usb]
syz_usb_connect$rtl8150(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_rtl8150], conn_descs const[0]) fd_usb_rtl8150 (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$rtl8150(fd fd_usb_rtl8150, descs ptr[in, vusb_descriptors_rtl8150], resps ptr[in, vusb_responses_rtl8150]) (timeout[300], remote_cover)
usb_device_descriptor_rtl8150 {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0xbda, 0x8150, 0, array[usb_config_descriptor_rtl8150, 1]]
} [packed]
usb_config_descriptor_rtl8150 {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_rtl8150]
} [packed]
usb_interface_descriptor_rtl8150 {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_rtl8150]
} [packed]
usb_endpoint_descriptors_rtl8150 {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_rtl8150 {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
RTL8150_REQ_GET_REGS ptr[in, vusb_response_t[RTL8150_REQT_READ, RTL8150_REQ_GET_REGS, array[int8, 0:6]]]
RTL8150_REQ_SET_REGS ptr[in, vusb_response_t[RTL8150_REQT_WRITE, RTL8150_REQ_SET_REGS, array[int8, 0:6]]]
} [packed]
define RTL8150_REQ_GET_REGS 0x05
define RTL8150_REQ_SET_REGS 0x05
define RTL8150_REQT_READ 0xc0
define RTL8150_REQT_WRITE 0x40
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# sierra_net driver specific descriptions.
resource fd_usb_sierra_net[fd_usb]
syz_usb_connect$sierra_net(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_sierra_net], conn_descs const[0]) fd_usb_sierra_net (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$sierra_net(fd fd_usb_sierra_net, descs ptr[in, vusb_descriptors_sierra_net], resps ptr[in, vusb_responses_sierra_net]) (timeout[300], remote_cover)
usb_device_descriptor_sierra_net {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x1199, 0x68a3, 0, array[usb_config_descriptor_sierra_net, 1]]
} [packed]
usb_config_descriptor_sierra_net {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_sierra_net]
} [packed]
usb_interface_descriptor_sierra_net {
iface usb_interface_descriptor_fixed_t[7, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_sierra_net]
} [packed]
# sierra_net driver does not expect fixed ep addresses, so refrain from being too specific here.
# As long as we ensure there are 3 endpoints, 2 bulk and 1 int, syzkaller should figure it out.
usb_endpoint_descriptors_sierra_net {
bulk_in usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
bulk_out usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_BULK_ATTR, int8], void]
status usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], const[USB_ENDPOINT_INT_ATTR, int8], void]
} [packed]
vusb_descriptors_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_sierra_net {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_CDC_GET_ENCAPSULATED_RESPONSE ptr[in, vusb_response_t[SIERRA_CMD_TYPE_IN, USB_CDC_GET_ENCAPSULATED_RESPONSE, array[int8, 1024]]]
USB_CDC_SEND_ENCAPSULATED_COMMANDT ptr[in, vusb_response_t[SIERRA_CMD_TYPE_OUT, USB_CDC_SEND_ENCAPSULATED_COMMAND, array[int8, 0:4]]]
} [packed]
define SIERRA_CMD_TYPE_IN (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
define SIERRA_CMD_TYPE_OUT (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# lan78xx driver specific descriptions.
# While these syz_* variants noticably help with the probe() process, they are not enough.
# This is due to a high number of control requests expected between the driver and the device.
include <drivers/net/usb/smsc95xx.h>
resource fd_usb_lan78xx[fd_usb]
syz_usb_connect$lan78xx(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_lan78xx], conn_descs const[0]) fd_usb_lan78xx (timeout[3000], prog_timeout[3000], remote_cover)
syz_usb_control_io$lan78xx(fd fd_usb_lan78xx, descs ptr[in, vusb_descriptors_lan78xx], resps ptr[in, vusb_responses_lan78xx]) (timeout[300], remote_cover)
usb_device_descriptor_lan78xx {
inner usb_device_descriptor_fixed_t[0x200, USB_CLASS_VENDOR_SPEC, USB_SUBCLASS_VENDOR_SPEC, 0xff, 64, 0x424, 0x7850, 0, array[usb_config_descriptor_lan78xx, 1]]
} [packed]
usb_config_descriptor_lan78xx {
inner usb_config_descriptor_fixed_t[1, 1, USB_CONFIG_ATT_ONE, 250, usb_interface_descriptor_lan78xx]
} [packed]
usb_interface_descriptor_lan78xx {
iface usb_interface_descriptor_fixed_t[0, 0, 3, USB_CLASS_VENDOR_SPEC, 0, 0, void, usb_endpoint_descriptors_lan78xx]
} [packed]
usb_endpoint_descriptors_lan78xx {
bulk_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_IN_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
bulk_out usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_BULK_OUT_ADDR, USB_ENDPOINT_BULK_ATTR, 512, 0, void]
int_in usb_endpoint_descriptor_fixed_t[USB_FIXED_ENDPOINT_INT_IN_ADDR, USB_ENDPOINT_INT_ATTR, 64, 1, void]
} [packed]
vusb_descriptors_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_descriptor_generic]
USB_DT_STRING ptr[in, vusb_descriptor_t[USB_TYPE_STANDARD, USB_DT_STRING, usb_string_descriptor]]
} [packed]
vusb_responses_lan78xx {
len len[parent, int32]
generic ptr[in, vusb_response_generic]
USB_REQ_GET_INTERFACE ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_INTERFACE, int8]]
USB_REQ_GET_CONFIGURATION ptr[in, vusb_response_t[USB_TYPE_STANDARD, USB_REQ_GET_CONFIGURATION, int8]]
USB_VENDOR_REQUEST_READ_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_READ_REGISTER, int32]]
USB_VENDOR_REQUEST_WRITE_REGISTER ptr[in, vusb_response_t[LAN78XX_REG_TYPE_OUT, USB_VENDOR_REQUEST_WRITE_REGISTER, int32]]
USB_VENDOR_REQUEST_GET_STATS ptr[in, vusb_response_t[LAN78XX_REG_TYPE_IN, USB_VENDOR_REQUEST_GET_STATS, array[int8, 47]]]
} [packed]
define LAN78XX_REG_TYPE_IN (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
define LAN78XX_REG_TYPE_OUT (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
]
|
| 471/2 |
2026/07/30 13:30 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 208833
output: 253
thoughts: 2092
Thoughts: **USB Device Enumeration and Endpoint Communication Strategy**
Okay, so I'm looking at how to interact with a USB device in this fuzzing environment. The key function here is `syz_usb_connect`. I initially thought I needed to deal with a `vusb_dev` structure, but it looks like `syz_usb_connect` actually takes a `usb_device_descriptor`. The problem is, this descriptor is strongly typed, and I need flexibility to craft custom descriptors, possibly with missing or differently sized endpoints. The underlying implementation in `executor/common_usb.h` suggests I can bypass the type checker by using `ANY` and providing a raw byte blob for the descriptor.
To construct this, it looks like:
1. `r0 = syz_usb_connect(3, AUTO, &AUTO=ANY=[@ANYBLOB="<descriptor_bytes>"], 0)` is the correct approach.
However, the initial thought of using `syz_usb_control_io` to provide `ep_responses` is slightly misleading. `syz_usb_connect` itself needs this to enumerate.
Now, endpoint interaction seems to involve `syz_usb_ep_write`. This is used to write data to a specific endpoint. I've got the idea!
So the plan is:
1. Connect the device with a custom descriptor using `syz_usb_connect`. This should return a file descriptor (`fd_usb`).
2. Write data to endpoint 0x84 using `syz_usb_ep_write` immediately after the device is connected. Something like `syz_usb_ep_write(r0, 0x84, AUTO, &AUTO="0000aa55")`.
3. Then proceed to the subsequent device interaction (`i2c` in this case).
The critical part is the timing. It looks like `syz_usb_connect` does *not* block indefinitely waiting for the probe to complete. It returns immediately after the device is configured, and the driver's `probe` function is then run, possibly concurrently. This means I *can* call `syz_usb_ep_write` sequentially. So no need for `async` to avoid deadlock, it's a synchronous operation to interact after device configuration!
|
| 472/2 |
2026/07/30 13:31 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, AUTO, &AUTO=ANY=[@ANYBLOB="12010002000000403b0904a10100000000010902200001010080000904000002ff00ff000705840340000107058802400000"], 0)
syz_usb_ep_write(r0, 0x84, AUTO, &AUTO="0000aa55")
r1 = syz_open_dev$i2c(&AUTO='/dev/i2c-#\x00', 0, 0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, &AUTO=""})
Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 473/2 |
2026/07/30 13:31 |
llm |
crash-repro-finder-compressor |
0m
Model:
Reply: ### 1. Approaches Tried and Results
* **Direct Device Opening**:
* Attempted opening `/dev/video0` and `/dev/i2c-0` directly using `syz_open_dev$video` and `syz_open_dev$I2C`.
* *Result*: Failed with syntax errors; syzkaller requires exact template strings like `"/dev/i2c-#\x00"`.
* **Generic HID Emulation**:
* Used `syz_usb_connect$hid` to connect generic HID device.
* *Result*: Target drivers (`si4713`, `au0828`, `go7007`) did not bind because syzkaller patches vendor/product IDs to match generic HID drivers.
* **Custom USB Descriptor Construction via Structs**:
* Attempted constructing custom `usb_device_descriptor` for `syz_usb_connect` to emulate `si4713` (Vendor `0x10c4`, Product `0x8244`, Class `USB_CLASS_HID`).
* *Result*: Failed due to syntax constraints (e.g., `AUTO` cannot be used for `FlagsType` or `ArrayType` fields, `void` fields must be `""`, and `bInterfaceClass` is hardcoded to `0` in generic definitions).
* **USB Emulation via Raw `ANY` Blobs**:
* Passed raw byte array for device descriptor using `&AUTO=ANY=[@ANYBLOB="..."]`.
* *Result*: Succeeded in bypassing struct constraints and forcing specific vendor/product IDs.
* **Target Driver Investigation**:
* **`si4713`**: Requires complex control message handshakes during `si4713_send_startup_command`. Handshake failure causes probe to fail before `si4713_register_i2c_adapter` is called. Dead-end.
* **`au0828`**: Checked `au0828_usb_disconnect` early-return bug. However, `au0828_usb_release` correctly calls `au0828_i2c_unregister` which calls `i2c_del_adapter`. Safe.
* **`go7007`**: Confirmed buggy. `go7007_usb_probe` registers `i2c_adapter` via `i2c_add_adapter`. If probe fails later (e.g., due to missing `ep_in[6]`), it jumps to `allocfail`, calls `go7007_usb_release(go)` and `kfree(go)` without calling `i2c_del_adapter`.
### 2. Current Hypotheses & Active Lines of Investigation
* **`go7007` I2C Adapter Leak & UAF**:
* `go7007_usb_probe` registers `i2c_adapter` embedded in `struct go7007`.
* If probe fails after registration, `go` is freed but `i2c_adapter` remains registered in `i2c_adapter_idr`.
* The freed memory block is reallocated (e.g., as `sk_buff` data) and then freed again.
* Userspace opens `/dev/i2c-X`, causing `i2c_get_adapter` to retrieve the dangling pointer from `i2c_adapter_idr`.
* Userspace calls `ioctl$I2C_SMBUS`, invoking `i2c_adapter_lock_bus` -> `i2c_adapter_depth`, which dereferences `adapter->dev.parent` (offset 264/368 depending on lockdep/debug configs) of the freed block, triggering the KASAN UAF.
* **Triggering Probe Failure**:
* Emulate `GO7007_BOARDID_PX_TV402U` (Vendor `0x093b`, Product `0xa104`, `bcdDevice = 0x0001`).
* Provide endpoints `0x84` (Interrupt IN) and `0x88` (Bulk IN), but omit `ep_in[6]` (Bulk IN for video).
* Provide a USB response for interrupt endpoint `0x84` returning `00 00 aa 55` to satisfy `go7007_read_interrupt` during `go7007_boot_encoder`.
* This allows `i2c_add_adapter` to succeed, but forces probe to fail at `if (!usb->usbdev->ep_in[6]) goto allocfail;`, triggering the leak.
### 3. Critical Code and Configuration Values
* **`go7007_usb_probe` Error Path (`drivers/media/usb/go7007/go7007-usb.c`)**:
```c
allocfail:
go7007_usb_release(go);
kfree(go);
return -ENOMEM;
```
* **`go7007_usb_release` (`drivers/media/usb/go7007/go7007-usb.c`)**:
```c
static void go7007_usb_release(struct go7007 *go)
{
struct go7007_usb *usb = go->hpi_context;
struct urb *vurb, *aurb;
int i;
if (usb->intr_urb) {
usb_kill_urb(usb->intr_urb);
kfree(usb->intr_urb->transfer_buffer);
usb_free_urb(usb->intr_urb);
}
/* Free USB-related structs */
for (i = 0; i < 8; ++i) {
vurb = usb->video_urbs[i];
if (vurb) {
usb_kill_urb(vurb);
kfree(vurb->transfer_buffer);
usb_free_urb(vurb);
}
aurb = usb->audio_urbs[i];
if (aurb) {
usb_kill_urb(aurb);
kfree(aurb->transfer_buffer);
usb_free_urb(aurb);
}
}
kfree(go->hpi_context);
}
```
* **Syzkaller Reproducer**:
```
r0 = syz_usb_connect(3, AUTO, &AUTO=@generic={0, &AUTO="12010002000000403b0904a10100000000010902200001010080000904000002ff00ff000705840340000107058802400000", 0, 0, &AUTO=[{0x84, &AUTO="0000aa55"}]}, 0)
r1 = syz_open_dev$i2c(&AUTO='/dev/i2c-#\x00', 0, 0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, &AUTO=""})
```
### 4. Potential Reasoning Loops & Repetitive Tool Calls
* **`sk_buff` Allocation Trace**: Do not assume the bug is in `netdevsim` or network subsystem because of the `sk_buff` allocation/free trace. KASAN reports the last owner of the physical page; the memory was simply reallocated as `sk_buff` data after `go7007` freed it, and then freed again before the dangling pointer was accessed.
* **`struct go7007` Size**: Do not assume `sizeof(struct go7007)` is always > 4096 bytes. Without debug options (like lockdep, spinlock debugging, media controller), the struct size is ~3988 bytes, which fits in `kmalloc-4k` and matches the KASAN report.
Tokens:
input: 232289
output: 1948
thoughts: 2877
|
| 474/2 |
2026/07/30 13:32 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 23657
output: 22
thoughts: 34
Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience:
**Debugging Device Driver Naming Conventions**
Right, that `syz_open_dev$i2c` name... something doesn't feel quite right about it. I need to verify that it aligns with the expected naming conventions for i2c device interactions. Let me double-check the authoritative source on this β the `dev_i2c.txt` file. I'm hoping that will offer the definitive answer regarding the proper format and potentially expose a simple typo, or suggest a more appropriate and consistent naming convention for this particular interaction. It's crucial to ensure our tooling, and the fuzzing process itself, is leveraging the right identifiers, or we're just chasing shadows.
|
| 475/2 |
2026/07/30 13:32 |
tool |
read-description |
0m
Args:
Results: map[Output:# Copyright 2018 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
include <uapi/linux/i2c-dev.h>
include <uapi/linux/i2c.h>
define I2C_MAX_BLOCK_1 (I2C_SMBUS_BLOCK_MAX + 1)
define I2C_MAX_BLOCK_2 (I2C_SMBUS_BLOCK_MAX + 2)
resource fd_i2c[fd]
syz_open_dev$I2C(dev ptr[in, string["/dev/i2c-#"]], id intptr, flags flags[open_flags]) fd_i2c
ioctl$I2C_RETRIES(fd fd_i2c, cmd const[I2C_RETRIES], arg intptr)
ioctl$I2C_TIMEOUT(fd fd_i2c, cmd const[I2C_TIMEOUT], arg intptr)
ioctl$I2C_SLAVE(fd fd_i2c, cmd const[I2C_SLAVE], arg intptr[0:0x3ff])
ioctl$I2C_SLAVE_FORCE(fd fd_i2c, cmd const[I2C_SLAVE_FORCE], arg intptr[0:0x3ff])
ioctl$I2C_TENBIT(fd fd_i2c, cmd const[I2C_TENBIT], arg boolptr)
ioctl$I2C_PEC(fd fd_i2c, cmd const[I2C_PEC], arg intptr)
ioctl$I2C_FUNCS(fd fd_i2c, cmd const[I2C_FUNCS], arg ptr[in, intptr])
ioctl$I2C_RDWR(fd fd_i2c, cmd const[I2C_RDWR], arg ptr[in, i2c_rdwr_ioctl_data])
ioctl$I2C_SMBUS(fd fd_i2c, cmd const[I2C_SMBUS], arg ptr[in, i2c_smbus_ioctl_data])
i2c_smbus_ioctl_data {
read_write bool8
command int8
size int32[I2C_SMBUS_QUICK:I2C_SMBUS_I2C_BLOCK_DATA]
data ptr[in, i2c_smbus_data]
}
i2c_smbus_data {
size int8[0:I2C_MAX_BLOCK_2]
block array[int8, I2C_MAX_BLOCK_1]
}
i2c_rdwr_ioctl_data {
msgs ptr[in, array[i2c_msg]]
nmsgs len[msgs, int32]
}
i2c_msg {
addr int16
flags flags[i2c_msg_flags, int16]
len len[buf, int16]
buf ptr[in, array[int8]]
}
i2c_msg_flags = I2C_M_RD, I2C_M_TEN, I2C_M_DMA_SAFE, I2C_M_RECV_LEN, I2C_M_NO_RD_ACK, I2C_M_IGNORE_NAK, I2C_M_REV_DIR_ADDR, I2C_M_NOSTART, I2C_M_STOP
]
|
| 476/2 |
2026/07/30 13:32 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 24715
output: 253
thoughts: 15
Thoughts: Okay, here's my interpretation of that thought as if it were my own, assuming I'm an expert:
**Identifying the Syzkaller Primitive**
Alright, the initial piece of the puzzle is clear: `syz_open_dev$I2C`. That's the key. This immediately tells me we're dealing with a syzkaller syscall wrapper, specifically targeting the `open()` system call, but specialized for an I2C device. Knowing this narrows down the scope considerably. We're not just looking at a generic `open()` issue, but something related to I2C device access. My focus needs to be on the interactions, configurations, or data passed *specifically* when opening an I2C device through this syzkaller-generated function. This informs my search terms and what I need to look for, to see if there is something specific to open I2C device that may be a problem. My investigation will be guided by my understanding of I2C device interaction at the kernel level, keeping in mind the typical structures and data exchanged during an `open()` call in this context.
|
| 477/2 |
2026/07/30 13:32 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, AUTO, &AUTO=ANY=[@ANYBLOB="12010002000000403b0904a10100000000010902200001010080000904000002ff00ff000705840340000107058802400000"], 0)
syz_usb_ep_write(r0, 0x84, AUTO, &AUTO="0000aa55")
r1 = syz_open_dev$I2C(&AUTO='/dev/i2c-#\x00', 0, 0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, &AUTO=""})
Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 478/2 |
2026/07/30 13:32 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 25282
output: 256
thoughts: 85
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience:
**Analyzing the I2C SMBus Data Structure**
Right, so I'm looking at this `i2c_smbus_data` structure. It's crucial to remember that it *is* a structure, a data container, and not some character string as I might've initially glossed over. I've got to unpack it properly.
Looking at the definition, it's pretty standard for SMBus transfers. We have a `size` field, which I'm inferring is an 8-bit integer array. The array ranges from 0 up to `I2C_MAX_BLOCK_2`, which probably sets an upper limit on the size of the block data. Then, and this is the core of the data payload, there is `block` which is an array of `int8` with a size given by `I2C_MAX_BLOCK_1`.
With this understanding, if I'm thinking about how to initialize it in a way that represents an "automatic" or default state, then `&AUTO={0, []}` becomes the obvious choice. I can set the `size` to 0, which likely indicates an empty block, and initialize the `block` array with an empty array.
|
| 479/2 |
2026/07/30 13:32 |
tool |
reproduce-crash |
0m
Error:
Args: map[ReproSyz:r0 = syz_usb_connect(3, AUTO, &AUTO=ANY=[@ANYBLOB="12010002000000403b0904a10100000000010902200001010080000904000002ff00ff000705840340000107058802400000"], 0)
syz_usb_ep_write(r0, 0x84, AUTO, &AUTO="0000aa55")
r1 = syz_open_dev$I2C(&AUTO='/dev/i2c-#\x00', 0, 0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, &AUTO={0, []}})
Sandbox:none]
Results: map[ExecutionCachedID: ReproducedBugTitle: ReproducedCrashReport:]
|
| 480/2 |
2026/07/30 13:32 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 25978
output: 252
thoughts: 203
Thoughts: **Reasoning Through I2C SMBus Data Structure Initialization**
Okay, so I'm looking at this `array[int8, I2C_MAX_BLOCK_1]`. Right, that's a fixed-size array within a struct. I remember, `I2C_MAX_BLOCK_1` is derived from `I2C_SMBUS_BLOCK_MAX + 1`, and that max value is 32, so this array holds 33 `int8` elements. Got it.
Now, the question is how to initialize this. I could either use `AUTO` for the entire struct, which *should* handle the nested array correctly, or I could explicitly provide all 33 zeroes. Hmmm, the zero initialization approach seems a bit clunky.
Maybe I can use `&AUTO={0, [0]}`. Wait, a fixed-size array within a struct will need all elements or `AUTO`?
But, wait a minute... If I use `&AUTO` *for the pointer* to `i2c_smbus_data`, then syzkaller will automatically generate the appropriate values, right? That seems cleaner and simpler. So, let's go with that. The final call should then look like this:
```
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, &AUTO})
```
That should work. Using `&AUTO` for the pointer to the `i2c_smbus_data` and let syzkaller figure it out.
|
| 481/2 |
2026/07/30 13:32 |
tool |
reproduce-crash |
2m
Args: map[ReproSyz:r0 = syz_usb_connect(3, AUTO, &AUTO=ANY=[@ANYBLOB="12010002000000403b0904a10100000000010902200001010080000904000002ff00ff000705840340000107058802400000"], 0)
syz_usb_ep_write(r0, 0x84, AUTO, &AUTO="0000aa55")
r1 = syz_open_dev$I2C(&AUTO='/dev/i2c-#\x00', 0, 0)
ioctl$I2C_SMBUS(r1, 0x720, &AUTO={0, 0, 0, &AUTO})
Sandbox:none]
Results: map[ExecutionCachedID:repro/d8ccde7fb7ff9cebb915310c53ed585bd30b0654 ReproducedBugTitle: ReproducedCrashReport:]
|
| 482/2 |
2026/07/30 13:34 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 26843
output: 83
thoughts: 54
Thoughts: Okay, here's my take on those thoughts, framed as my own:
**Initial Assessment and Targeted Verification**
Well, that's a relief, it didn't crash. My immediate thought is to zero in on what *did* happen, or rather, *didn't* happen. Let's dig into that `go7007-usb.c` file and, specifically, I need to verify a couple of key points. First, was `go7007_usb_probe` even invoked? If it wasn't called, then the problem lies upstream, and I am looking in the wrong place. Assuming it *was* called, I need to confirm whether the function reached `ep_in[6]`. If `ep_in[6]` has been hit, then it's a very targeted problem, and I'll know where to start looking.
|
| 483/2 |
2026/07/30 13:34 |
tool |
get-file-coverage |
0m
Error:
Args: map[ExecutionCachedID:repro/d8ccde7fb7ff9cebb915310c53ed585bd30b0654 Filename:drivers/media/usb/go7007/go7007-usb.c Functions:[]]
Results: map[CoveredFunctions:<nil> Snippets:<nil>]
|
| 484/2 |
2026/07/30 13:34 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 27211
output: 56
thoughts: 82
Thoughts: **Missing Piece: The go7007-usb.c Module**
Hold on a second, I don't recall seeing anything specific about `go7007-usb.c` in the material! That seems like a pretty significant oversight. Why did that get skipped? I need to understand this. Okay, let's see... the vendor ID is `0x093b` and the product ID is `0xa104`. Right, right. Time to dive into the code. I'll need to check the `go7007_usb_id_table` within `drivers/media/usb/go7007/go7007-usb.c`. That's where the relevant device identifiers should be. Let's see what's in there.
|
| 485/2 |
2026/07/30 13:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/usb/go7007/go7007-usb.c Name:go7007_usb_id_table]
Results: map[SourceCode: 506: static const struct usb_device_id go7007_usb_id_table[] = {
507: {
508: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
509: USB_DEVICE_ID_MATCH_INT_INFO,
510: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
511: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
512: .bcdDevice_lo = 0x200, /* Revision number of XMen */
513: .bcdDevice_hi = 0x200,
514: .bInterfaceClass = 255,
515: .bInterfaceSubClass = 0,
516: .bInterfaceProtocol = 255,
517: .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN,
518: },
519: {
520: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
521: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
522: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
523: .bcdDevice_lo = 0x202, /* Revision number of Matrix II */
524: .bcdDevice_hi = 0x202,
525: .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II,
526: },
527: {
528: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
529: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
530: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
531: .bcdDevice_lo = 0x204, /* Revision number of Matrix */
532: .bcdDevice_hi = 0x204, /* Reloaded */
533: .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD,
534: },
535: {
536: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
537: USB_DEVICE_ID_MATCH_INT_INFO,
538: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
539: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
540: .bcdDevice_lo = 0x205, /* Revision number of XMen-II */
541: .bcdDevice_hi = 0x205,
542: .bInterfaceClass = 255,
543: .bInterfaceSubClass = 0,
544: .bInterfaceProtocol = 255,
545: .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_II,
546: },
547: {
548: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
549: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
550: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
551: .bcdDevice_lo = 0x208, /* Revision number of Star Trek */
552: .bcdDevice_hi = 0x208,
553: .driver_info = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK,
554: },
555: {
556: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
557: USB_DEVICE_ID_MATCH_INT_INFO,
558: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
559: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
560: .bcdDevice_lo = 0x209, /* Revision number of XMen-III */
561: .bcdDevice_hi = 0x209,
562: .bInterfaceClass = 255,
563: .bInterfaceSubClass = 0,
564: .bInterfaceProtocol = 255,
565: .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_III,
566: },
567: {
568: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
569: .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
570: .idProduct = 0x7007, /* Product ID of GO7007SB chip */
571: .bcdDevice_lo = 0x210, /* Revision number of Matrix */
572: .bcdDevice_hi = 0x210, /* Revolution */
573: .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV,
574: },
575: {
576: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
577: .idVendor = 0x093b, /* Vendor ID of Plextor */
578: .idProduct = 0xa102, /* Product ID of M402U */
579: .bcdDevice_lo = 0x1, /* revision number of Blueberry */
580: .bcdDevice_hi = 0x1,
581: .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_M402U,
582: },
583: {
584: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
585: .idVendor = 0x093b, /* Vendor ID of Plextor */
586: .idProduct = 0xa104, /* Product ID of TV402U */
587: .bcdDevice_lo = 0x1,
588: .bcdDevice_hi = 0x1,
589: .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U,
590: },
591: {
592: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
593: .idVendor = 0x10fd, /* Vendor ID of Anubis Electronics */
594: .idProduct = 0xde00, /* Product ID of Lifeview LR192 */
595: .bcdDevice_lo = 0x1,
596: .bcdDevice_hi = 0x1,
597: .driver_info = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192,
598: },
599: {
600: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
601: .idVendor = 0x1943, /* Vendor ID Sensoray */
602: .idProduct = 0x2250, /* Product ID of 2250/2251 */
603: .bcdDevice_lo = 0x1,
604: .bcdDevice_hi = 0x1,
605: .driver_info = (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250,
606: },
607: {
608: .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
609: .idVendor = 0x06e1, /* Vendor ID of ADS Technologies */
610: .idProduct = 0x0709, /* Product ID of DVD Xpress DX2 */
611: .bcdDevice_lo = 0x204,
612: .bcdDevice_hi = 0x204,
613: .driver_info = (kernel_ulong_t)GO7007_BOARDID_ADS_USBAV_709,
614: },
615: { } /* Terminating entry */
616: };
SourceFile:drivers/media/usb/go7007/go7007-usb.c]
|
| 486/2 |
2026/07/30 13:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 30059
output: 23
thoughts: 788
Thoughts: **USB Device Descriptor Deep Dive**
Okay, let's see... I've got a device with vendor ID `0x093b`, product ID `0xa104`, and `bcdDevice = 0x1`. Now, let's dig into the descriptor data. Analyzing this byte stream, I can see the standard device descriptor layout:
`12` (bLength)
`01` (bDescriptorType)
`00 02` (bcdUSB)
`00` (bDeviceClass)
`00` (bDeviceSubClass)
`00` (bDeviceProtocol)
`40` (bMaxPacketSize0)
`3b 09` (idVendor = 0x093b)
`04 a1` (idProduct = 0xa104)
`01 00` (bcdDevice = 0x0001)
`00` (iManufacturer)
`00` (iProduct)
`00` (iSerialNumber)
`01` (bNumConfigurations)
Next, the configuration descriptor is:
`09 02 20 00 01 01 00 80 00`
Which breaks down as:
`09` (bLength)
`02` (bDescriptorType)
`20 00` (wTotalLength = 32)
`01` (bNumInterfaces)
`01` (bConfigurationValue)
`00` (iConfiguration)
`80` (bmAttributes)
`00` (bMaxPower)
Then the interface descriptor:
`09 04 00 00 02 ff 00 ff 00`
`09` (bLength)
`04` (bDescriptorType)
`00` (bInterfaceNumber)
`00` (bAlternateSetting)
`02` (bNumEndpoints)
`ff` (bInterfaceClass)
`00` (bInterfaceSubClass)
`ff` (bInterfaceProtocol)
`00` (iInterface)
And finally, the endpoint descriptors:
Endpoint 1: `07 05 84 03 40 00 01` - Interrupt endpoint.
Endpoint 2: `07 05 88 02 40 00 00` - Bulk endpoint.
Now, let's verify the `wTotalLength`. 9 (config) + 9 (interface) + 7 (ep1) + 7 (ep2) = 32. Yep, that checks out perfectly. The descriptors appear well-formed and consistent. So, why isn't this device working as expected? Perhaps, the `go7007-usb` module isn't compiled into the kernel? That's the next logical step. I'll need to check the kernel configuration to be sure.
|
| 487/2 |
2026/07/30 13:35 |
tool |
grepper |
0m
Args: map[Expression:CONFIG_VIDEO_GO7007]
Results: map[Output:drivers/media/usb/Makefile=27=obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
drivers/media/usb/Makefile:28:obj-$(CONFIG_VIDEO_GO7007) += go7007/
drivers/media/usb/Makefile-29-obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
--
drivers/media/usb/go7007/Makefile-1-# SPDX-License-Identifier: GPL-2.0
drivers/media/usb/go7007/Makefile:2:obj-$(CONFIG_VIDEO_GO7007) += go7007.o
drivers/media/usb/go7007/Makefile:3:obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o
drivers/media/usb/go7007/Makefile:4:obj-$(CONFIG_VIDEO_GO7007_LOADER) += go7007-loader.o
drivers/media/usb/go7007/Makefile:5:obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o
drivers/media/usb/go7007/Makefile-6-
--
drivers/media/usb/go7007/Makefile=10=s2250-y := s2250-board.o
drivers/media/usb/go7007/Makefile-11-
drivers/media/usb/go7007/Makefile:12:ccflags-$(CONFIG_VIDEO_GO7007_LOADER:m=y) += -I $(srctree)/drivers/media/common
]
|
| 488/2 |
2026/07/30 13:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 31970
output: 23
thoughts: 110
Thoughts: **Kernel Configuration Deep Dive**
Okay, so I need to figure out if `CONFIG_VIDEO_GO7007` is enabled in the syzkaller kernel config. Hmm, I can't just directly inspect the config file, can I? No, of course not. What's the workaround? Ah, right, I can check the `get-coverage-files` output from *any* of the syzkaller runs. If `go7007` appears in that list, I know it's compiled.
Shoot, the last run didn't show it. So, is it even *compiled*? That's the key question now. I need to confirm if the kernel even *contains* `go7007`. Let me check if `go7007_usb_probe` is present. That should give me a definitive answer on whether the driver is built in or as a module.
|
| 489/2 |
2026/07/30 13:35 |
tool |
grepper |
0m
Args: map[Expression:go7007_usb_probe]
Results: map[Output:drivers/media/usb/go7007/go7007-usb.c=1032=static struct i2c_adapter go7007_usb_adap_templ = {
--
drivers/media/usb/go7007/go7007-usb.c-1039-
drivers/media/usb/go7007/go7007-usb.c:1040:static int go7007_usb_probe(struct usb_interface *intf,
drivers/media/usb/go7007/go7007-usb.c-1041- const struct usb_device_id *id)
--
drivers/media/usb/go7007/go7007-usb.c=1347=static struct usb_driver go7007_usb_driver = {
drivers/media/usb/go7007/go7007-usb.c-1348- .name = "go7007",
drivers/media/usb/go7007/go7007-usb.c:1349: .probe = go7007_usb_probe,
drivers/media/usb/go7007/go7007-usb.c-1350- .disconnect = go7007_usb_disconnect,
]
|
| 490/2 |
2026/07/30 13:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 32649
output: 21
thoughts: 1964
Thoughts: **Analyzing a Slab-Use-After-Free Bug: A Deep Dive**
Okay, let's break this down. My initial hunch was that the `go7007` driver, which I was examining because of its USB interface interaction, might be responsible. First, I wanted to determine if it was even compiled into the kernel. If `CONFIG_VIDEO_GO7007` isn't set, it won't be, and then it can't be the culprit. I initially thought to check the `kallsyms` table, but then realized I could use tools like `codesearch-find-references` or `git-log` (though that's for source, not compiled binaries). I created a syz program to trigger the driver and check coverage, but it returned no coverage. Was that because it wasn't compiled, or merely wasn't reached?
I considered that `syz_usb_connect` should trigger `usb_probe_interface`, which iterates drivers, and therefore if `go7007` was registered, it should be called. Then I went to check `go7007_usb_id_table` to make sure the interface was a match, but my device descriptor had `bInterfaceClass = 255`, where the `go7007_usb_id_table` has a different match. So it should have matched and been called, and it wasn't. I added a wait to the syz program but it didn't crash, so perhaps it wasn't the driver.
Okay, let's rethink. I'm dealing with a `KASAN: slab-use-after-free in i2c_adapter_lock_bus` error. The adapter was allocated by `nsim_dev_trap_skb_build`. The KASAN report details this allocation and subsequent free within `nsim_dev_trap_report_work`. It's a 4096-byte allocation (kmalloc-4k). I then noted that the buggy address is within the 4096-byte region (264 bytes in). This suggests the `i2c_adapter` might have been *embedded* in a struct, which was then freed, and *that* memory reallocated for an `sk_buff`! If so, it would have been freed after being allocated for the sk_buff!
Crucially, the KASAN report only shows the *last* allocation and free of the *physical page*. So, either the `i2c_adapter` was allocated and freed before the `sk_buff` allocation, or after. It's the former: if the `i2c_adapter` was freed, *then* the page reused as `sk_buff` data, *and* then freed again, KASAN reports that last bit. This perfectly aligns with my hypothesis: the `i2c_adapter` memory was leaked, freed, and subsequently reused.
The allocation/free are in the same task, and from the same call stack. The allocation is `nsim_dev_trap_skb_build`, and the free is `nsim_dev_trap_report_work`. This is an skb structure that contains the slab for the i2c adapter.
This means the `i2c_adapter` must have been allocated *before*, and was not allocated or freed within `nsim_dev_trap_skb_build`. This narrows it down considerably. Which driver registered and then freed the `i2c_adapter` without unregistering it? My memory of `go7007_usb_probe` makes me think of other drivers, which adds to my concern about the i2c adapter.
Let's search the kernel code for `i2c_add_adapter` or `i2c_bit_add_bus`, checking for error paths that might free without calling `i2c_del_adapter`. That's where I need to focus my investigation.
|
| 491/2 |
2026/07/30 13:35 |
tool |
grepper |
0m
Args: map[Expression:i2c_add_adapter]
Results: map[Output:
Full output is too long, showing 500 out of 1138 lines.
Use more precise expression if possible.
Documentation/driver-api/driver-model/devres.rst=280=I2C
Documentation/driver-api/driver-model/devres.rst:281: devm_i2c_add_adapter()
Documentation/driver-api/driver-model/devres.rst-282- devm_i2c_new_dummy_device()
--
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c=160=struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev,
--
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c-186- i2c->adapter.algo = &amdgpu_atombios_i2c_algo;
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c:187: ret = devm_i2c_add_adapter(dev->dev, &i2c->adapter);
drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c-188- if (ret)
--
drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c=727=int smu_v11_0_i2c_control_init(struct amdgpu_device *adev)
--
drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c-747-
drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c:748: res = devm_i2c_add_adapter(adev->dev, control);
drivers/gpu/drm/amd/amdgpu/smu_v11_0_i2c.c-749- if (res)
--
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c=3230=static int dm_oem_i2c_hw_init(struct amdgpu_device *adev)
--
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c-3244-
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:3245: r = devm_i2c_add_adapter(adev->dev, &oem_i2c->base);
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c-3246- if (r) {
--
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c=9543=static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
--
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c-9564- aconnector->i2c = i2c;
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:9565: res = devm_i2c_add_adapter(dm->adev->dev, &i2c->base);
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c-9566-
--
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c=1666=static int arcturus_i2c_control_init(struct smu_context *smu)
--
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c-1685-
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c:1686: res = devm_i2c_add_adapter(adev->dev, control);
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c-1687- if (res) {
--
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c=2881=static int navi10_i2c_control_init(struct smu_context *smu)
--
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c-2900-
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c:2901: res = devm_i2c_add_adapter(adev->dev, control);
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c-2902- if (res) {
--
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c=2591=static int sienna_cichlid_i2c_control_init(struct smu_context *smu)
--
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c-2610-
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c:2611: res = devm_i2c_add_adapter(adev->dev, control);
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c-2612- if (res) {
--
drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c=1507=static int aldebaran_i2c_control_init(struct smu_context *smu)
--
drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c-1523-
drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c:1524: res = devm_i2c_add_adapter(adev->dev, control);
drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c-1525- if (res) {
--
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c=2764=static int smu_v13_0_0_i2c_control_init(struct smu_context *smu)
--
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c-2782-
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c:2783: res = devm_i2c_add_adapter(adev->dev, control);
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c-2784- if (res) {
--
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c=2526=static int smu_v13_0_6_i2c_control_init(struct smu_context *smu)
--
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c-2544-
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c:2545: res = devm_i2c_add_adapter(adev->dev, control);
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c-2546- if (res) {
--
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c=1996=static int smu_v14_0_2_i2c_control_init(struct smu_context *smu)
--
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c-2014-
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c:2015: res = devm_i2c_add_adapter(adev->dev, control);
drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c-2016- if (res) {
--
drivers/gpu/drm/bridge/inno-hdmi.c=1030=static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi)
--
drivers/gpu/drm/bridge/inno-hdmi.c-1050-
drivers/gpu/drm/bridge/inno-hdmi.c:1051: ret = devm_i2c_add_adapter(hdmi->dev, adap);
drivers/gpu/drm/bridge/inno-hdmi.c-1052- if (ret) {
--
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c=716=static struct i2c_adapter *dw_hdmi_qp_i2c_adapter(struct dw_hdmi_qp *hdmi)
--
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c-736-
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c:737: ret = devm_i2c_add_adapter(hdmi->dev, adap);
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c-738- if (ret) {
--
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c=509=static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi)
--
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c-528-
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c:529: ret = i2c_add_adapter(adap);
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c-530- if (ret) {
--
drivers/gpu/drm/display/drm_dp_helper.c=2398=int drm_dp_aux_register(struct drm_dp_aux *aux)
--
drivers/gpu/drm/display/drm_dp_helper.c-2416-
drivers/gpu/drm/display/drm_dp_helper.c:2417: ret = i2c_add_adapter(&aux->ddc);
drivers/gpu/drm/display/drm_dp_helper.c-2418- if (ret) {
--
drivers/gpu/drm/display/drm_dp_mst_topology.c=5982=static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port)
--
drivers/gpu/drm/display/drm_dp_mst_topology.c-5998-
drivers/gpu/drm/display/drm_dp_mst_topology.c:5999: return i2c_add_adapter(&aux->ddc);
drivers/gpu/drm/display/drm_dp_mst_topology.c-6000-}
--
drivers/gpu/drm/gma500/cdv_intel_dp.c=223=i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
--
drivers/gpu/drm/gma500/cdv_intel_dp.c-229- return error;
drivers/gpu/drm/gma500/cdv_intel_dp.c:230: error = i2c_add_adapter(adapter);
drivers/gpu/drm/gma500/cdv_intel_dp.c-231- return error;
--
drivers/gpu/drm/gma500/intel_gmbus.c=387=int gma_intel_setup_gmbus(struct drm_device *dev)
--
drivers/gpu/drm/gma500/intel_gmbus.c-423- bus->adapter.algo = &gmbus_algorithm;
drivers/gpu/drm/gma500/intel_gmbus.c:424: ret = i2c_add_adapter(&bus->adapter);
drivers/gpu/drm/gma500/intel_gmbus.c-425- if (ret)
--
drivers/gpu/drm/gma500/psb_intel_sdvo.c=2426=psb_intel_sdvo_init_ddc_proxy(struct psb_intel_sdvo *sdvo,
--
drivers/gpu/drm/gma500/psb_intel_sdvo.c-2434-
drivers/gpu/drm/gma500/psb_intel_sdvo.c:2435: return i2c_add_adapter(&sdvo->ddc) == 0;
drivers/gpu/drm/gma500/psb_intel_sdvo.c-2436-}
--
drivers/gpu/drm/i915/display/intel_gmbus.c=903=int intel_gmbus_setup(struct intel_display *display)
--
drivers/gpu/drm/i915/display/intel_gmbus.c-960-
drivers/gpu/drm/i915/display/intel_gmbus.c:961: ret = i2c_add_adapter(&bus->adapter);
drivers/gpu/drm/i915/display/intel_gmbus.c-962- if (ret) {
--
drivers/gpu/drm/i915/display/intel_sdvo.c=3350=intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc,
--
drivers/gpu/drm/i915/display/intel_sdvo.c-3366-
drivers/gpu/drm/i915/display/intel_sdvo.c:3367: return i2c_add_adapter(&ddc->ddc);
drivers/gpu/drm/i915/display/intel_sdvo.c-3368-}
--
drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c=269=static int mtk_hdmi_ddc_probe(struct platform_device *pdev)
--
drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c-300-
drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c:301: ret = i2c_add_adapter(&ddc->adap);
drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c-302- if (ret < 0) {
--
drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c=343=static int mtk_hdmi_ddc_v2_probe(struct platform_device *pdev)
--
drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c-377-
drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c:378: ret = devm_i2c_add_adapter(dev, &ddc->adap);
drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c-379- if (ret < 0)
--
drivers/gpu/drm/msm/hdmi/hdmi_i2c.c=243=struct i2c_adapter *msm_hdmi_i2c_init(struct hdmi *hdmi)
--
drivers/gpu/drm/msm/hdmi/hdmi_i2c.c-265-
drivers/gpu/drm/msm/hdmi/hdmi_i2c.c:266: ret = i2c_add_adapter(i2c);
drivers/gpu/drm/msm/hdmi/hdmi_i2c.c-267- if (ret)
--
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxch.c=186=nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func,
--
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxch.c-203- aux->i2c.algo = &nvkm_i2c_aux_i2c_algo;
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxch.c:204: return i2c_add_adapter(&aux->i2c);
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxch.c-205-}
--
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c=208=nvkm_i2c_bus_ctor(const struct nvkm_i2c_bus_func *func,
--
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c-249- bus->i2c.algo = &nvkm_i2c_bus_algo;
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c:250: ret = i2c_add_adapter(&bus->i2c);
drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c-251- }
--
drivers/gpu/drm/radeon/radeon_i2c.c=903=struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
--
drivers/gpu/drm/radeon/radeon_i2c.c-933- i2c->adapter.algo = &radeon_i2c_algo;
drivers/gpu/drm/radeon/radeon_i2c.c:934: ret = devm_i2c_add_adapter(dev->dev, &i2c->adapter);
drivers/gpu/drm/radeon/radeon_i2c.c-935- if (ret)
--
drivers/gpu/drm/radeon/radeon_i2c.c-943- i2c->adapter.algo = &radeon_atom_i2c_algo;
drivers/gpu/drm/radeon/radeon_i2c.c:944: ret = i2c_add_adapter(&i2c->adapter);
drivers/gpu/drm/radeon/radeon_i2c.c-945- if (ret)
--
drivers/gpu/drm/rockchip/rk3066_hdmi.c=643=static struct i2c_adapter *rk3066_hdmi_i2c_adapter(struct rk3066_hdmi *hdmi)
--
drivers/gpu/drm/rockchip/rk3066_hdmi.c-663-
drivers/gpu/drm/rockchip/rk3066_hdmi.c:664: ret = devm_i2c_add_adapter(hdmi->dev, adap);
drivers/gpu/drm/rockchip/rk3066_hdmi.c-665- if (ret) {
--
drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c=287=int sun4i_hdmi_i2c_create(struct device *dev, struct sun4i_hdmi *hdmi)
--
drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c-308-
drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c:309: ret = i2c_add_adapter(adap);
drivers/gpu/drm/sun4i/sun4i_hdmi_i2c.c-310- if (ret)
--
drivers/gpu/drm/tests/drm_connector_test.c=79=static int drm_test_connector_init(struct kunit *test)
--
drivers/gpu/drm/tests/drm_connector_test.c-97-
drivers/gpu/drm/tests/drm_connector_test.c:98: ret = i2c_add_adapter(&priv->ddc);
drivers/gpu/drm/tests/drm_connector_test.c-99- KUNIT_ASSERT_EQ(test, ret, 0);
--
drivers/hid/hid-cp2112.c=1218=static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
--
drivers/hid/hid-cp2112.c-1339- hid_device_io_start(hdev);
drivers/hid/hid-cp2112.c:1340: ret = i2c_add_adapter(&dev->adap);
drivers/hid/hid-cp2112.c-1341- hid_device_io_stop(hdev);
--
drivers/hid/hid-ft260.c=960=static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id)
--
drivers/hid/hid-ft260.c-1027- i2c_set_adapdata(&dev->adap, dev);
drivers/hid/hid-ft260.c:1028: ret = i2c_add_adapter(&dev->adap);
drivers/hid/hid-ft260.c-1029- if (ret) {
--
drivers/hid/hid-mcp2221.c=1237=static int mcp2221_probe(struct hid_device *hdev,
--
drivers/hid/hid-mcp2221.c-1305- i2c_set_adapdata(&mcp->adapter, mcp);
drivers/hid/hid-mcp2221.c:1306: ret = devm_i2c_add_adapter(&hdev->dev, &mcp->adapter);
drivers/hid/hid-mcp2221.c-1307- if (ret) {
--
drivers/i2c/algos/i2c-algo-bit.c=675=int i2c_bit_add_bus(struct i2c_adapter *adap)
drivers/i2c/algos/i2c-algo-bit.c-676-{
drivers/i2c/algos/i2c-algo-bit.c:677: return __i2c_bit_add_bus(adap, i2c_add_adapter);
drivers/i2c/algos/i2c-algo-bit.c-678-}
--
drivers/i2c/algos/i2c-algo-pca.c=532=int i2c_pca_add_bus(struct i2c_adapter *adap)
--
drivers/i2c/algos/i2c-algo-pca.c-539-
drivers/i2c/algos/i2c-algo-pca.c:540: return i2c_add_adapter(adap);
drivers/i2c/algos/i2c-algo-pca.c-541-}
--
drivers/i2c/algos/i2c-algo-pcf.c=349=int i2c_pcf_add_bus(struct i2c_adapter *adap)
--
drivers/i2c/algos/i2c-algo-pcf.c-360-
drivers/i2c/algos/i2c-algo-pcf.c:361: rval = i2c_add_adapter(adap);
drivers/i2c/algos/i2c-algo-pcf.c-362-
--
drivers/i2c/busses/i2c-ali1535.c=486=static int ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-ali1535.c-500- "SMBus ALI1535 adapter at %04x", ali1535_offset);
drivers/i2c/busses/i2c-ali1535.c:501: ret = i2c_add_adapter(&ali1535_adapter);
drivers/i2c/busses/i2c-ali1535.c-502- if (ret)
--
drivers/i2c/busses/i2c-ali1563.c=396=static int ali1563_probe(struct pci_dev *dev,
--
drivers/i2c/busses/i2c-ali1563.c-406- "SMBus ALi 1563 Adapter @ %04x", ali1563_smba);
drivers/i2c/busses/i2c-ali1563.c:407: error = i2c_add_adapter(&ali1563_adapter);
drivers/i2c/busses/i2c-ali1563.c-408- if (error)
--
drivers/i2c/busses/i2c-ali15x3.c=473=static int ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-ali15x3.c-487- "SMBus ALI15X3 adapter at %04x", ali15x3_smba);
drivers/i2c/busses/i2c-ali15x3.c:488: ret = i2c_add_adapter(&ali15x3_adapter);
drivers/i2c/busses/i2c-ali15x3.c-489- if (ret)
--
drivers/i2c/busses/i2c-altera.c=383=static int altr_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-altera.c-457-
drivers/i2c/busses/i2c-altera.c:458: ret = i2c_add_adapter(&idev->adapter);
drivers/i2c/busses/i2c-altera.c-459- if (ret) {
--
drivers/i2c/busses/i2c-amd-asf-plat.c=299=static int amd_asf_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-amd-asf-plat.c-348-
drivers/i2c/busses/i2c-amd-asf-plat.c:349: return devm_i2c_add_adapter(dev, &asf_dev->adap);
drivers/i2c/busses/i2c-amd-asf-plat.c-350-}
--
drivers/i2c/busses/i2c-amd-mp2-plat.c=245=static int i2c_amd_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-amd-mp2-plat.c-314- /* Attach to the i2c layer */
drivers/i2c/busses/i2c-amd-mp2-plat.c:315: ret = i2c_add_adapter(&i2c_dev->adap);
drivers/i2c/busses/i2c-amd-mp2-plat.c-316-
--
drivers/i2c/busses/i2c-amd756.c=314=static int amd756_probe(struct pci_dev *pdev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-amd756.c-371-
drivers/i2c/busses/i2c-amd756.c:372: error = i2c_add_adapter(&amd756_smbus);
drivers/i2c/busses/i2c-amd756.c-373- if (error)
--
drivers/i2c/busses/i2c-amd8111.c=422=static int amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-amd8111.c-455- pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);
drivers/i2c/busses/i2c-amd8111.c:456: error = i2c_add_adapter(&smbus->adapter);
drivers/i2c/busses/i2c-amd8111.c-457- if (error)
--
drivers/i2c/busses/i2c-aspeed.c=998=static int aspeed_i2c_probe_bus(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-aspeed.c-1072-
drivers/i2c/busses/i2c-aspeed.c:1073: ret = i2c_add_adapter(&bus->adap);
drivers/i2c/busses/i2c-aspeed.c-1074- if (ret < 0)
--
drivers/i2c/busses/i2c-axxia.c=720=static int axxia_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-axxia.c-782-
drivers/i2c/busses/i2c-axxia.c:783: ret = i2c_add_adapter(&idev->adapter);
drivers/i2c/busses/i2c-axxia.c-784- if (ret)
--
drivers/i2c/busses/i2c-bcm-iproc.c=1088=static int bcm_iproc_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-bcm-iproc.c-1158-
drivers/i2c/busses/i2c-bcm-iproc.c:1159: return i2c_add_adapter(adap);
drivers/i2c/busses/i2c-bcm-iproc.c-1160-}
--
drivers/i2c/busses/i2c-bcm-kona.c=737=static int bcm_kona_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-bcm-kona.c-845-
drivers/i2c/busses/i2c-bcm-kona.c:846: rc = i2c_add_adapter(adap);
drivers/i2c/busses/i2c-bcm-kona.c-847- if (rc)
--
drivers/i2c/busses/i2c-bcm2835.c=408=static int bcm2835_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-bcm2835.c-488-
drivers/i2c/busses/i2c-bcm2835.c:489: ret = i2c_add_adapter(adap);
drivers/i2c/busses/i2c-bcm2835.c-490- if (ret)
--
drivers/i2c/busses/i2c-brcmstb.c=612=static int brcmstb_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-brcmstb.c-691- adap->dev.of_node = pdev->dev.of_node;
drivers/i2c/busses/i2c-brcmstb.c:692: rc = i2c_add_adapter(adap);
drivers/i2c/busses/i2c-brcmstb.c-693- if (rc)
--
drivers/i2c/busses/i2c-cadence.c=1493=static int cdns_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-cadence.c-1599-
drivers/i2c/busses/i2c-cadence.c:1600: ret = i2c_add_adapter(&id->adap);
drivers/i2c/busses/i2c-cadence.c-1601- if (ret < 0)
--
drivers/i2c/busses/i2c-cht-wc.c=426=static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-cht-wc.c-490- i2c_set_adapdata(&adap->adapter, adap);
drivers/i2c/busses/i2c-cht-wc.c:491: ret = i2c_add_adapter(&adap->adapter);
drivers/i2c/busses/i2c-cht-wc.c-492- if (ret)
--
drivers/i2c/busses/i2c-cp2615.c=282=cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id)
--
drivers/i2c/busses/i2c-cp2615.c-311-
drivers/i2c/busses/i2c-cp2615.c:312: ret = i2c_add_adapter(adap);
drivers/i2c/busses/i2c-cp2615.c-313- if (ret)
--
drivers/i2c/busses/i2c-cros-ec-tunnel.c=242=static int ec_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-cros-ec-tunnel.c-280-
drivers/i2c/busses/i2c-cros-ec-tunnel.c:281: err = i2c_add_adapter(&bus->adap);
drivers/i2c/busses/i2c-cros-ec-tunnel.c-282- if (err)
--
drivers/i2c/busses/i2c-digicolor.c=288=static int dc_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-digicolor.c-340-
drivers/i2c/busses/i2c-digicolor.c:341: ret = i2c_add_adapter(&i2c->adap);
drivers/i2c/busses/i2c-digicolor.c-342- if (ret < 0) {
--
drivers/i2c/busses/i2c-diolan-u2c.c=430=static int diolan_u2c_probe(struct usb_interface *interface,
--
drivers/i2c/busses/i2c-diolan-u2c.c-474- /* and finally attach to i2c layer */
drivers/i2c/busses/i2c-diolan-u2c.c:475: ret = i2c_add_adapter(&dev->adapter);
drivers/i2c/busses/i2c-diolan-u2c.c-476- if (ret < 0)
--
drivers/i2c/busses/i2c-dln2.c=187=static int dln2_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-dln2.c-224- /* and finally attach to i2c layer */
drivers/i2c/busses/i2c-dln2.c:225: ret = i2c_add_adapter(&dln2->adapter);
drivers/i2c/busses/i2c-dln2.c-226- if (ret < 0)
--
drivers/i2c/busses/i2c-eg20t.c=712=static int pch_i2c_probe(struct pci_dev *pdev,
--
drivers/i2c/busses/i2c-eg20t.c-783- if (ret) {
drivers/i2c/busses/i2c-eg20t.c:784: pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i);
drivers/i2c/busses/i2c-eg20t.c-785- goto err_add_adapter;
--
drivers/i2c/busses/i2c-emev2.c=360=static int em_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-emev2.c-403-
drivers/i2c/busses/i2c-emev2.c:404: ret = i2c_add_adapter(&priv->adap);
drivers/i2c/busses/i2c-emev2.c-405- if (ret)
--
drivers/i2c/busses/i2c-exynos5.c=887=static int exynos5_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-exynos5.c-960-
drivers/i2c/busses/i2c-exynos5.c:961: ret = i2c_add_adapter(&i2c->adap);
drivers/i2c/busses/i2c-exynos5.c-962- if (ret < 0)
--
drivers/i2c/busses/i2c-fsi.c=677=static int fsi_i2c_probe(struct fsi_device *fsi_dev)
--
drivers/i2c/busses/i2c-fsi.c-728-
drivers/i2c/busses/i2c-fsi.c:729: rc = i2c_add_adapter(&port->adapter);
drivers/i2c/busses/i2c-fsi.c-730- if (rc < 0) {
--
drivers/i2c/busses/i2c-gxp.c=507=static int gxp_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-gxp.c-572-
drivers/i2c/busses/i2c-gxp.c:573: rc = i2c_add_adapter(adapter);
drivers/i2c/busses/i2c-gxp.c-574- if (rc)
--
drivers/i2c/busses/i2c-hisi.c=457=static int hisi_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-hisi.c-506-
drivers/i2c/busses/i2c-hisi.c:507: ret = devm_i2c_add_adapter(dev, adapter);
drivers/i2c/busses/i2c-hisi.c-508- if (ret)
--
drivers/i2c/busses/i2c-hix5hd2.c=390=static int hix5hd2_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-hix5hd2.c-454-
drivers/i2c/busses/i2c-hix5hd2.c:455: ret = i2c_add_adapter(&priv->adap);
drivers/i2c/busses/i2c-hix5hd2.c-456- if (ret < 0)
--
drivers/i2c/busses/i2c-i801.c=1537=static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-i801.c-1664-
drivers/i2c/busses/i2c-i801.c:1665: err = i2c_add_adapter(&priv->adapter);
drivers/i2c/busses/i2c-i801.c-1666- if (err) {
--
drivers/i2c/busses/i2c-ibm_iic.c=682=static int iic_probe(struct platform_device *ofdev)
--
drivers/i2c/busses/i2c-ibm_iic.c-738-
drivers/i2c/busses/i2c-ibm_iic.c:739: ret = i2c_add_adapter(adap);
drivers/i2c/busses/i2c-ibm_iic.c-740- if (ret < 0)
--
drivers/i2c/busses/i2c-imx-lpi2c.c=1471=static int lpi2c_imx_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-imx-lpi2c.c-1566-
drivers/i2c/busses/i2c-imx-lpi2c.c:1567: ret = i2c_add_adapter(&lpi2c_imx->adapter);
drivers/i2c/busses/i2c-imx-lpi2c.c-1568- if (ret)
--
drivers/i2c/busses/i2c-isch.c=274=static int smbus_sch_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-isch.c-300-
drivers/i2c/busses/i2c-isch.c:301: return devm_i2c_add_adapter(dev, &priv->adapter);
drivers/i2c/busses/i2c-isch.c-302-}
--
drivers/i2c/busses/i2c-ismt.c=883=ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
--
drivers/i2c/busses/i2c-ismt.c-965-
drivers/i2c/busses/i2c-ismt.c:966: err = i2c_add_adapter(&priv->adapter);
drivers/i2c/busses/i2c-ismt.c-967- if (err)
--
drivers/i2c/busses/i2c-jz4780.c=761=static int jz4780_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-jz4780.c-833-
drivers/i2c/busses/i2c-jz4780.c:834: ret = i2c_add_adapter(&i2c->adap);
drivers/i2c/busses/i2c-jz4780.c-835- if (ret < 0)
--
drivers/i2c/busses/i2c-keba.c=507=static int ki2c_probe(struct auxiliary_device *auxdev,
--
drivers/i2c/busses/i2c-keba.c-546-
drivers/i2c/busses/i2c-keba.c:547: ret = devm_i2c_add_adapter(dev, adap);
drivers/i2c/busses/i2c-keba.c-548- if (ret) {
--
drivers/i2c/busses/i2c-ljca.c=273=static int ljca_i2c_probe(struct auxiliary_device *auxdev,
--
drivers/i2c/busses/i2c-ljca.c-307-
drivers/i2c/busses/i2c-ljca.c:308: ret = devm_i2c_add_adapter(&auxdev->dev, &ljca_i2c->adap);
drivers/i2c/busses/i2c-ljca.c-309- if (ret)
--
drivers/i2c/busses/i2c-lpc2k.c=345=static int i2c_lpc2k_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-lpc2k.c-416-
drivers/i2c/busses/i2c-lpc2k.c:417: ret = i2c_add_adapter(&i2c->adap);
drivers/i2c/busses/i2c-lpc2k.c-418- if (ret < 0)
--
drivers/i2c/busses/i2c-ls2x-v2.c=475=static int loongson2_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-ls2x-v2.c-523-
drivers/i2c/busses/i2c-ls2x-v2.c:524: return devm_i2c_add_adapter(dev, adap);
drivers/i2c/busses/i2c-ls2x-v2.c-525-}
--
drivers/i2c/busses/i2c-ls2x.c=287=static int ls2x_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-ls2x.c-327-
drivers/i2c/busses/i2c-ls2x.c:328: return devm_i2c_add_adapter(dev, adap);
drivers/i2c/busses/i2c-ls2x.c-329-}
--
drivers/i2c/busses/i2c-mchp-pci1xxxx.c=1129=static int pci1xxxx_i2c_probe_pci(struct pci_dev *pdev,
--
drivers/i2c/busses/i2c-mchp-pci1xxxx.c-1181-
drivers/i2c/busses/i2c-mchp-pci1xxxx.c:1182: ret = devm_i2c_add_adapter(dev, &i2c->adap);
drivers/i2c/busses/i2c-mchp-pci1xxxx.c-1183- if (ret)
--
drivers/i2c/busses/i2c-meson.c=456=static int meson_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-meson.c-527-
drivers/i2c/busses/i2c-meson.c:528: ret = i2c_add_adapter(&i2c->adap);
drivers/i2c/busses/i2c-meson.c-529- if (ret < 0) {
--
drivers/i2c/busses/i2c-microchip-corei2c.c=538=static int mchp_corei2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-microchip-corei2c.c-608-
drivers/i2c/busses/i2c-microchip-corei2c.c:609: ret = i2c_add_adapter(&idev->adapter);
drivers/i2c/busses/i2c-microchip-corei2c.c-610- if (ret) {
--
drivers/i2c/busses/i2c-mt65xx.c=1385=static int mtk_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-mt65xx.c-1500- i2c_set_adapdata(&i2c->adap, i2c);
drivers/i2c/busses/i2c-mt65xx.c:1501: ret = i2c_add_adapter(&i2c->adap);
drivers/i2c/busses/i2c-mt65xx.c-1502- if (ret)
--
drivers/i2c/busses/i2c-mt7621.c=268=static int mtk_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-mt7621.c-311-
drivers/i2c/busses/i2c-mt7621.c:312: ret = i2c_add_adapter(adap);
drivers/i2c/busses/i2c-mt7621.c-313- if (ret < 0)
--
drivers/i2c/busses/i2c-nct6694.c=145=static int nct6694_i2c_probe(struct platform_device *pdev)
--
drivers/i2c/busses/i2c-nct6694.c-180-
drivers/i2c/busses/i2c-nct6694.c:181: return devm_i2c_add_adapter(dev, &data->adapter);
drivers/i2c/busses/i2c-nct6694.c-182-}
--
drivers/i2c/busses/i2c-nforce2.c=304=static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg,
--
drivers/i2c/busses/i2c-nforce2.c-344-
drivers/i2c/busses/i2c-nforce2.c:345: error = i2c_add_adapter(&smbus->adapter);
drivers/i2c/busses/i2c-nforce2.c-346- if (error) {
--
drivers/i2c/busses/i2c-nomadik.c=1082=static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
]
|
| 492/2 |
2026/07/30 13:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 48771
output: 54
thoughts: 288
Thoughts: **Analyzing a Potential Kernel Bug**
Okay, so it's not *just* `go7007` causing this issue. I'm trying to trace down this memory leak that we've seen, specifically the one where `i2c_add_adapter` gets called but `i2c_del_adapter` doesn't. We know that `go7007` has this known issue: it calls `i2c_add_adapter`, and if `ep_in[6]` is missing, it skips `i2c_del_adapter` before freeing the struct, which causes a leak.
First, I need to confirm if `go7007` is even compiled into the syzkaller kernel. If it's not, we can rule it out immediately. My instinct is to check the kernel config for `CONFIG_VIDEO_GO7007`, but I don't have direct access to that. I could try `codesearch-find-references` for `go7007_usb_probe`, but that seems like it would just search the source code and I need to know if it's compiled, not just present. So, no.
Hmm... Let's see if another driver exhibits the same flawed behavior. I need to widen the search. What about `au0828`? I'll check `au0828_usb_probe` and see what it does. `au0828` calls `au0828_i2c_register`, so I need to see if it unregisters in its error paths. I'll focus on `au0828_usb_probe` and its cleanup.
|
| 493/2 |
2026/07/30 13:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/usb/au0828/au0828-core.c Name:au0828_usb_probe]
Results: map[SourceCode: 643: static int au0828_usb_probe(struct usb_interface *interface,
644: const struct usb_device_id *id)
645: {
646: int ifnum;
647: int retval = 0;
648:
649: struct au0828_dev *dev;
650: struct usb_device *usbdev = interface_to_usbdev(interface);
651:
652: ifnum = interface->altsetting->desc.bInterfaceNumber;
653:
654: if (ifnum != 0)
655: return -ENODEV;
656:
657: dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
658: le16_to_cpu(usbdev->descriptor.idVendor),
659: le16_to_cpu(usbdev->descriptor.idProduct),
660: ifnum);
661:
662: /*
663: * Make sure we have 480 Mbps of bandwidth, otherwise things like
664: * video stream wouldn't likely work, since 12 Mbps is generally
665: * not enough even for most Digital TV streams.
666: */
667: if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
668: pr_err("au0828: Device initialization failed.\n");
669: pr_err("au0828: Device must be connected to a high-speed USB 2.0 port.\n");
670: return -ENODEV;
671: }
672:
673: dev = kzalloc_obj(*dev);
674: if (dev == NULL) {
675: pr_err("%s() Unable to allocate memory\n", __func__);
676: return -ENOMEM;
677: }
678:
679: mutex_init(&dev->lock);
680: mutex_lock(&dev->lock);
681: mutex_init(&dev->mutex);
682: mutex_init(&dev->dvb.lock);
683: dev->usbdev = usbdev;
684: dev->boardnr = id->driver_info;
685: dev->board = au0828_boards[dev->boardnr];
686:
687: /* Initialize the media controller */
688: retval = au0828_media_device_init(dev, usbdev);
689: if (retval) {
690: pr_err("%s() au0828_media_device_init failed\n",
691: __func__);
692: mutex_unlock(&dev->lock);
693: kfree(dev);
694: return retval;
695: }
696:
697: retval = au0828_v4l2_device_register(interface, dev);
698: if (retval) {
699: au0828_usb_v4l2_media_release(dev);
700: mutex_unlock(&dev->lock);
701: kfree(dev);
702: return retval;
703: }
704:
705: /* Power Up the bridge */
706: au0828_write(dev, REG_600, 1 << 4);
707:
708: /* Bring up the GPIO's and supporting devices */
709: au0828_gpio_setup(dev);
710:
711: /* I2C */
712: au0828_i2c_register(dev);
713:
714: /* Setup */
715: au0828_card_setup(dev);
716:
717: /*
718: * Store the pointer to the au0828_dev so it can be accessed in
719: * au0828_usb_disconnect
720: */
721: usb_set_intfdata(interface, dev);
722:
723: /* Analog TV */
724: retval = au0828_analog_register(dev, interface);
725: if (retval) {
726: pr_err("%s() au0828_analog_register failed to register on V4L2\n",
727: __func__);
728: mutex_unlock(&dev->lock);
729: goto done;
730: }
731:
732: /* Digital TV */
733: retval = au0828_dvb_register(dev);
734: if (retval)
735: pr_err("%s() au0828_dvb_register failed\n",
736: __func__);
737:
738: /* Remote controller */
739: au0828_rc_register(dev);
740:
741: pr_info("Registered device AU0828 [%s]\n",
742: dev->board.name == NULL ? "Unset" : dev->board.name);
743:
744: mutex_unlock(&dev->lock);
745:
746: retval = au0828_media_device_register(dev, usbdev);
747:
748: done:
749: if (retval < 0)
750: au0828_usb_disconnect(interface);
751:
752: return retval;
753: }
SourceFile:drivers/media/usb/au0828/au0828-core.c]
|
| 494/2 |
2026/07/30 13:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 51169
output: 54
thoughts: 50
Thoughts: **Analyzing the USB Probe and Disconnect Functions**
Okay, so I'm looking at this `au0828_usb_probe` function, and something just clicked. It looks like it checks the return value, `retval`. And if it's less than zero, which indicates an error, it calls `au0828_usb_disconnect` immediately, passing in the `interface` variable. That's a critical bit of logic. It means the disconnect function is intended to clean up resources or handle errors if the initial probing of the USB device fails. I need to understand what this disconnect function actually *does*. I need to see if it makes sense in the context of device initialization and error handling. So, I need to investigate `au0828_usb_disconnect` right now. Let's see what we are dealing with.
|
| 495/2 |
2026/07/30 13:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/usb/au0828/au0828-core.c Name:au0828_usb_disconnect]
Results: map[SourceCode: 163: static void au0828_usb_disconnect(struct usb_interface *interface)
164: {
165: struct au0828_dev *dev = usb_get_intfdata(interface);
166:
167: dprintk(1, "%s()\n", __func__);
168:
169: /* there is a small window after disconnect, before
170: dev->usbdev is NULL, for poll (e.g: IR) try to access
171: the device and fill the dmesg with error messages.
172: Set the status so poll routines can check and avoid
173: access after disconnect.
174: */
175: set_bit(DEV_DISCONNECTED, &dev->dev_state);
176:
177: au0828_rc_unregister(dev);
178: /* Digital TV */
179: au0828_dvb_unregister(dev);
180:
181: usb_set_intfdata(interface, NULL);
182: mutex_lock(&dev->mutex);
183: dev->usbdev = NULL;
184: mutex_unlock(&dev->mutex);
185: if (au0828_analog_unregister(dev)) {
186: /*
187: * No need to call au0828_usb_release() if V4L2 is enabled,
188: * as this is already called via au0828_usb_v4l2_release()
189: */
190: return;
191: }
192: au0828_usb_release(dev);
193: }
SourceFile:drivers/media/usb/au0828/au0828-core.c]
|
| 496/2 |
2026/07/30 13:35 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 51985
output: 54
thoughts: 291
Thoughts: **Analyzing the Device Disconnect Sequence**
Okay, let's see. My initial thought is, how does `au0828_usb_disconnect` get its device (`dev`)? Right, it uses `usb_get_intfdata(interface)`. I need to ensure the correct `dev` is being passed.
Now, in `au0828_usb_probe`, `usb_set_intfdata(interface, dev)` is *definitely* called *before* `au0828_analog_register`. Good, that seems logical. But what happens if `au0828_analog_register` fails? The code jumps to `done`, and then it calls `au0828_usb_disconnect`. I need to track that.
Hmm, this reminds me of something else. What if there are failures in other places? Specifically, what if `au0828_media_device_init` fails? It frees `dev` and returns. And what if `au0828_v4l2_device_register` fails? Same situation: `kfree(dev)` and returns. So in both these cases, we're not hitting `au0828_usb_disconnect`.
But what if, *again*, `au0828_analog_register` fails, as we were originally considering? Then the flow jumps to `done`, and calls `au0828_usb_disconnect`. And `au0828_usb_disconnect` then retrieves `dev` via `usb_get_intfdata`. Then it calls `au0828_analog_unregister(dev)`.
Wait a minute, if `au0828_analog_unregister` *returns* true (let's assume that means it's "in use", or something similar), the function returns *early*. This might be a critical point of failure. I need to understand that return condition of `au0828_analog_unregister`. I'm going to look at that function next.
|
| 497/2 |
2026/07/30 13:36 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/usb/au0828/au0828-core.c Name:au0828_analog_unregister]
Results: map[SourceCode: 920: /* ------------------------------------------------------------------
921: V4L2 interface
922: ------------------------------------------------------------------*/
923: /*
924: * au0828_analog_unregister
925: * unregister v4l2 devices
926: */
927: int au0828_analog_unregister(struct au0828_dev *dev)
928: {
929: dprintk(1, "au0828_analog_unregister called\n");
930:
931: /* No analog TV */
932: if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
933: return 0;
934:
935: mutex_lock(&au0828_sysfs_lock);
936: vb2_video_unregister_device(&dev->vdev);
937: vb2_video_unregister_device(&dev->vbi_dev);
938: mutex_unlock(&au0828_sysfs_lock);
939:
940: v4l2_device_disconnect(&dev->v4l2_dev);
941: v4l2_device_put(&dev->v4l2_dev);
942:
943: return 1;
944: }
SourceFile:drivers/media/usb/au0828/au0828-video.c]
|
| 498/2 |
2026/07/30 13:36 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 53207
output: 59
thoughts: 247
Thoughts: **Analyzing the Device Unregistration Logic**
Okay, hold on a minute. This `au0828_analog_unregister` function⦠it returns 1 if the input type isn't defined, right? Specifically, if `AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED`. And if it *does* return 1, the `au0828_usb_disconnect` function in the calling context bails out immediately. That's a crucial detail. Looking at the code:
```c
if (au0828_analog_unregister(dev)) {
/*
* No need to call au0828_usb_release() if V4L2 is enabled,
* as this is already called via au0828_usb_v4l2_release()
*/
return;
}
au0828_usb_release(dev);
```
So, if `au0828_analog_unregister` signals an error (returns 1), we *don't* call `au0828_usb_release`. Instead, the logic implies that the unregistration of analog components and the associated cleanup are somehow handled by `au0828_usb_v4l2_release` in the V4L2 context. The comment suggests there's an assumption being made here, that `au0828_usb_v4l2_release` handles the necessary release in the error condition. I need to verify that, specifically when the V4L2 device is enabled. I need to examine `au0828_usb_v4l2_release` to understand the full picture.
|
| 499/2 |
2026/07/30 13:36 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/usb/au0828/au0828-video.c Name:au0828_usb_v4l2_release]
Results: map[SourceCode: 635: static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
636: {
637: struct au0828_dev *dev =
638: container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
639:
640: v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
641: v4l2_device_unregister(&dev->v4l2_dev);
642: au0828_usb_v4l2_media_release(dev);
643: au0828_usb_release(dev);
644: }
SourceFile:drivers/media/usb/au0828/au0828-video.c]
|
| 500/2 |
2026/07/30 13:36 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 54150
output: 54
thoughts: 64
Thoughts: Okay, here's my interpretation of that thought process, assuming I'm already deep in the weeds with this code:
**Release Sequence Confirmation**
Alright, so I've been tracing through this USB video capture driver, and finally, it's clicked. It's clear that when `au0828_usb_v4l2_release` is called, it *does* indeed make that crucial call to `au0828_usb_release(dev)`. That's the first key point. It confirms the higher-level release function correctly initiates the USB-specific cleanup.
And then, looking deeper into `au0828_usb_release`, I see that it triggers `au0828_i2c_unregister(dev)`. This is significant because it means the I2C interface associated with the device is properly unregistered as part of the USB release sequence. This confirms the order of operations for resource deallocation, making sure we shut down the I2C interface used by the driver for communication with the device. It's exactly the sequence I'd expect to see, ensuring a clean and safe shutdown.
|
| 501/2 |
2026/07/30 13:36 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/usb/au0828/au0828-core.c Name:au0828_usb_release]
Results: map[SourceCode: 153: void au0828_usb_release(struct au0828_dev *dev)
154: {
155: au0828_unregister_media_device(dev);
156:
157: /* I2C */
158: au0828_i2c_unregister(dev);
159:
160: kfree(dev);
161: }
SourceFile:drivers/media/usb/au0828/au0828-core.c]
|
| 502/2 |
2026/07/30 13:36 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 54682
output: 56
thoughts: 61
Thoughts: Okay, let's see...
**Analyzing the Potential Risks**
Right, so `au0828` looks like it's behaving itself, no immediate red flags there. Now, the `si4713` module... that's where I need to dig a little deeper. The `si4713_usb_probe` function is interesting because it calls `si4713_register_i2c_adapter`. My immediate concern is error handling. If `si4713_register_i2c_adapter` *fails* at some point, does the driver implement the necessary unregistration and cleanup routines to roll things back properly? I need to verify that it's robust and prevents any lingering resource issues or unexpected behavior. That's a critical point for the overall system stability.
|
| 503/2 |
2026/07/30 13:36 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/radio/si4713/radio-usb-si4713.c Name:usb_si4713_probe]
Results: map[SourceCode: 410: /* check if the device is present and register with v4l and usb if it is */
411: static int usb_si4713_probe(struct usb_interface *intf,
412: const struct usb_device_id *id)
413: {
414: struct si4713_usb_device *radio;
415: struct i2c_adapter *adapter;
416: struct v4l2_subdev *sd;
417: int retval;
418:
419: dev_info(&intf->dev, "Si4713 development board discovered: (%04X:%04X)\n",
420: id->idVendor, id->idProduct);
421:
422: /* Initialize local device structure */
423: radio = kzalloc_obj(struct si4713_usb_device);
424: if (radio)
425: radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
426:
427: if (!radio || !radio->buffer) {
428: dev_err(&intf->dev, "kmalloc for si4713_usb_device failed\n");
429: kfree(radio);
430: return -ENOMEM;
431: }
432:
433: mutex_init(&radio->lock);
434:
435: radio->usbdev = interface_to_usbdev(intf);
436: radio->intf = intf;
437: usb_set_intfdata(intf, &radio->v4l2_dev);
438:
439: retval = si4713_start_seq(radio);
440: if (retval < 0)
441: goto err_v4l2;
442:
443: retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
444: if (retval < 0) {
445: dev_err(&intf->dev, "couldn't register v4l2_device\n");
446: goto err_v4l2;
447: }
448:
449: retval = si4713_register_i2c_adapter(radio);
450: if (retval < 0) {
451: dev_err(&intf->dev, "could not register i2c device\n");
452: goto err_i2cdev;
453: }
454:
455: adapter = &radio->i2c_adapter;
456: sd = v4l2_i2c_new_subdev_board(&radio->v4l2_dev, adapter,
457: &si4713_board_info, NULL);
458: radio->v4l2_subdev = sd;
459: if (!sd) {
460: dev_err(&intf->dev, "cannot get v4l2 subdevice\n");
461: retval = -ENODEV;
462: goto del_adapter;
463: }
464:
465: radio->vdev.ctrl_handler = sd->ctrl_handler;
466: radio->v4l2_dev.release = usb_si4713_video_device_release;
467: strscpy(radio->vdev.name, radio->v4l2_dev.name,
468: sizeof(radio->vdev.name));
469: radio->vdev.v4l2_dev = &radio->v4l2_dev;
470: radio->vdev.fops = &usb_si4713_fops;
471: radio->vdev.ioctl_ops = &usb_si4713_ioctl_ops;
472: radio->vdev.lock = &radio->lock;
473: radio->vdev.release = video_device_release_empty;
474: radio->vdev.vfl_dir = VFL_DIR_TX;
475: radio->vdev.device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
476:
477: video_set_drvdata(&radio->vdev, radio);
478:
479: retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
480: if (retval < 0) {
481: dev_err(&intf->dev, "could not register video device\n");
482: goto del_adapter;
483: }
484:
485: dev_info(&intf->dev, "V4L2 device registered as %s\n",
486: video_device_node_name(&radio->vdev));
487:
488: return 0;
489:
490: del_adapter:
491: i2c_del_adapter(adapter);
492: err_i2cdev:
493: v4l2_device_unregister(&radio->v4l2_dev);
494: err_v4l2:
495: kfree(radio->buffer);
496: kfree(radio);
497: return retval;
498: }
SourceFile:drivers/media/radio/si4713/radio-usb-si4713.c]
|
| 504/2 |
2026/07/30 13:36 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 56547
output: 54
thoughts: 40
Thoughts: Okay, here's my take on those thoughts, framed as my own:
**Reviewing Adapter Deletion Procedures**
Alright, so the `si4713` driver is definitely on the right track. It's properly using `i2c_del_adapter(adapter)` within its `del_adapter` function. That's good, that's what we want to see.
Now, let's take another look at the `go7007` driver. I need to make sure *that* one is handled correctly as well, because this pattern is critical for resource management and preventing I2C bus contention. Gotta be thorough. Time to revisit that code.
|
| 505/2 |
2026/07/30 13:36 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/usb/go7007/go7007-usb.c Name:go7007_usb_probe]
Results: map[SourceCode:1040: static int go7007_usb_probe(struct usb_interface *intf,
1041: const struct usb_device_id *id)
1042: {
1043: struct go7007 *go;
1044: struct go7007_usb *usb;
1045: const struct go7007_usb_board *board;
1046: struct usb_device *usbdev = interface_to_usbdev(intf);
1047: struct usb_host_endpoint *ep;
1048: unsigned num_i2c_devs;
1049: char *name;
1050: int video_pipe, i, v_urb_len;
1051:
1052: pr_debug("probing new GO7007 USB board\n");
1053:
1054: switch (id->driver_info) {
1055: case GO7007_BOARDID_MATRIX_II:
1056: name = "WIS Matrix II or compatible";
1057: board = &board_matrix_ii;
1058: break;
1059: case GO7007_BOARDID_MATRIX_RELOAD:
1060: name = "WIS Matrix Reloaded or compatible";
1061: board = &board_matrix_reload;
1062: break;
1063: case GO7007_BOARDID_MATRIX_REV:
1064: name = "WIS Matrix Revolution or compatible";
1065: board = &board_matrix_revolution;
1066: break;
1067: case GO7007_BOARDID_STAR_TREK:
1068: name = "WIS Star Trek or compatible";
1069: board = &board_star_trek;
1070: break;
1071: case GO7007_BOARDID_XMEN:
1072: name = "WIS XMen or compatible";
1073: board = &board_xmen;
1074: break;
1075: case GO7007_BOARDID_XMEN_II:
1076: name = "WIS XMen II or compatible";
1077: board = &board_xmen;
1078: break;
1079: case GO7007_BOARDID_XMEN_III:
1080: name = "WIS XMen III or compatible";
1081: board = &board_xmen;
1082: break;
1083: case GO7007_BOARDID_PX_M402U:
1084: name = "Plextor PX-M402U";
1085: board = &board_matrix_ii;
1086: break;
1087: case GO7007_BOARDID_PX_TV402U:
1088: name = "Plextor PX-TV402U (unknown tuner)";
1089: board = &board_px_tv402u;
1090: break;
1091: case GO7007_BOARDID_LIFEVIEW_LR192:
1092: dev_err(&intf->dev, "The Lifeview TV Walker Ultra is not supported. Sorry!\n");
1093: return -ENODEV;
1094: #if 0
1095: name = "Lifeview TV Walker Ultra";
1096: board = &board_lifeview_lr192;
1097: #endif
1098: break;
1099: case GO7007_BOARDID_SENSORAY_2250:
1100: dev_info(&intf->dev, "Sensoray 2250 found\n");
1101: name = "Sensoray 2250/2251";
1102: board = &board_sensoray_2250;
1103: break;
1104: case GO7007_BOARDID_ADS_USBAV_709:
1105: name = "ADS Tech DVD Xpress DX2";
1106: board = &board_ads_usbav_709;
1107: break;
1108: default:
1109: dev_err(&intf->dev, "unknown board ID %d!\n",
1110: (unsigned int)id->driver_info);
1111: return -ENODEV;
1112: }
1113:
1114: go = go7007_alloc(&board->main_info, &intf->dev);
1115: if (go == NULL)
1116: return -ENOMEM;
1117:
1118: usb = kzalloc_obj(struct go7007_usb);
1119: if (usb == NULL) {
1120: kfree(go);
1121: return -ENOMEM;
1122: }
1123:
1124: usb->board = board;
1125: usb->usbdev = usbdev;
1126: usb_make_path(usbdev, go->bus_info, sizeof(go->bus_info));
1127: go->board_id = id->driver_info;
1128: strscpy(go->name, name, sizeof(go->name));
1129: if (board->flags & GO7007_USB_EZUSB)
1130: go->hpi_ops = &go7007_usb_ezusb_hpi_ops;
1131: else
1132: go->hpi_ops = &go7007_usb_onboard_hpi_ops;
1133: go->hpi_context = usb;
1134:
1135: ep = usb->usbdev->ep_in[4];
1136: if (!ep)
1137: goto allocfail;
1138:
1139: /* Allocate the URB and buffer for receiving incoming interrupts */
1140: usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
1141: if (usb->intr_urb == NULL)
1142: goto allocfail;
1143: usb->intr_urb->transfer_buffer = kmalloc_array(2, sizeof(u16),
1144: GFP_KERNEL);
1145: if (usb->intr_urb->transfer_buffer == NULL)
1146: goto allocfail;
1147:
1148: if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK)
1149: usb_fill_bulk_urb(usb->intr_urb, usb->usbdev,
1150: usb_rcvbulkpipe(usb->usbdev, 4),
1151: usb->intr_urb->transfer_buffer, 2*sizeof(u16),
1152: go7007_usb_readinterrupt_complete, go);
1153: else
1154: usb_fill_int_urb(usb->intr_urb, usb->usbdev,
1155: usb_rcvintpipe(usb->usbdev, 4),
1156: usb->intr_urb->transfer_buffer, 2*sizeof(u16),
1157: go7007_usb_readinterrupt_complete, go, 8);
1158: usb_set_intfdata(intf, &go->v4l2_dev);
1159:
1160: /* Boot the GO7007 */
1161: if (go7007_boot_encoder(go, go->board_info->flags &
1162: GO7007_BOARD_USE_ONBOARD_I2C) < 0)
1163: goto allocfail;
1164:
1165: /* Register the EZ-USB I2C adapter, if we're using it */
1166: if (board->flags & GO7007_USB_EZUSB_I2C) {
1167: memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
1168: sizeof(go7007_usb_adap_templ));
1169: mutex_init(&usb->i2c_lock);
1170: go->i2c_adapter.dev.parent = go->dev;
1171: i2c_set_adapdata(&go->i2c_adapter, go);
1172: if (i2c_add_adapter(&go->i2c_adapter) < 0) {
1173: dev_err(go->dev, "error: i2c_add_adapter failed\n");
1174: goto allocfail;
1175: }
1176: go->i2c_adapter_online = 1;
1177: }
1178:
1179: /* Pelco and Adlink reused the XMen and XMen-III vendor and product
1180: * IDs for their own incompatible designs. We can detect XMen boards
1181: * by probing the sensor, but there is no way to probe the sensors on
1182: * the Pelco and Adlink designs so we default to the Adlink. If it
1183: * is actually a Pelco, the user must set the assume_endura module
1184: * parameter. */
1185: if ((go->board_id == GO7007_BOARDID_XMEN ||
1186: go->board_id == GO7007_BOARDID_XMEN_III) &&
1187: go->i2c_adapter_online) {
1188: union i2c_smbus_data data;
1189:
1190: /* Check to see if register 0x0A is 0x76 */
1191: i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,
1192: I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);
1193: if (data.byte != 0x76) {
1194: if (assume_endura) {
1195: go->board_id = GO7007_BOARDID_ENDURA;
1196: usb->board = board = &board_endura;
1197: go->board_info = &board->main_info;
1198: strscpy(go->name, "Pelco Endura",
1199: sizeof(go->name));
1200: } else {
1201: u16 channel;
1202:
1203: /* read channel number from GPIO[1:0] */
1204: if (go7007_read_addr(go, 0x3c81, &channel))
1205: goto allocfail;
1206:
1207: channel &= 0x3;
1208: go->board_id = GO7007_BOARDID_ADLINK_MPG24;
1209: usb->board = board = &board_adlink_mpg24;
1210: go->board_info = &board->main_info;
1211: go->channel_number = channel;
1212: snprintf(go->name, sizeof(go->name),
1213: "Adlink PCI-MPG24, channel #%d",
1214: channel);
1215: }
1216: go7007_update_board(go);
1217: }
1218: }
1219:
1220: num_i2c_devs = go->board_info->num_i2c_devs;
1221:
1222: /* Probe the tuner model on the TV402U */
1223: if (go->board_id == GO7007_BOARDID_PX_TV402U) {
1224: /* Board strapping indicates tuner model */
1225: if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3,
1226: 1) < 0) {
1227: dev_err(go->dev, "GPIO read failed!\n");
1228: goto allocfail;
1229: }
1230: switch (go->usb_buf[0] >> 6) {
1231: case 1:
1232: go->tuner_type = TUNER_SONY_BTF_PG472Z;
1233: go->std = V4L2_STD_PAL;
1234: strscpy(go->name, "Plextor PX-TV402U-EU",
1235: sizeof(go->name));
1236: break;
1237: case 2:
1238: go->tuner_type = TUNER_SONY_BTF_PK467Z;
1239: go->std = V4L2_STD_NTSC_M_JP;
1240: num_i2c_devs -= 2;
1241: strscpy(go->name, "Plextor PX-TV402U-JP",
1242: sizeof(go->name));
1243: break;
1244: case 3:
1245: go->tuner_type = TUNER_SONY_BTF_PB463Z;
1246: num_i2c_devs -= 2;
1247: strscpy(go->name, "Plextor PX-TV402U-NA",
1248: sizeof(go->name));
1249: break;
1250: default:
1251: pr_debug("unable to detect tuner type!\n");
1252: break;
1253: }
1254: /* Configure tuner mode selection inputs connected
1255: * to the EZ-USB GPIO output pins */
1256: if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
1257: NULL, 0, 0) < 0) {
1258: dev_err(go->dev, "GPIO write failed!\n");
1259: goto allocfail;
1260: }
1261: }
1262:
1263: /* Print a nasty message if the user attempts to use a USB2.0 device in
1264: * a USB1.1 port. There will be silent corruption of the stream. */
1265: if ((board->flags & GO7007_USB_EZUSB) &&
1266: usbdev->speed != USB_SPEED_HIGH)
1267: dev_err(go->dev, "*** WARNING *** This device must be connected to a USB 2.0 port! Attempting to capture video through a USB 1.1 port will result in stream corruption, even at low bitrates!\n");
1268:
1269: /* Allocate the URBs and buffers for receiving the video stream */
1270: if (board->flags & GO7007_USB_EZUSB) {
1271: if (!usb->usbdev->ep_in[6])
1272: goto allocfail;
1273: v_urb_len = 1024;
1274: video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);
1275: } else {
1276: if (!usb->usbdev->ep_in[1])
1277: goto allocfail;
1278: v_urb_len = 512;
1279: video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
1280: }
1281: for (i = 0; i < 8; ++i) {
1282: usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
1283: if (usb->video_urbs[i] == NULL)
1284: goto allocfail;
1285: usb->video_urbs[i]->transfer_buffer =
1286: kmalloc(v_urb_len, GFP_KERNEL);
1287: if (usb->video_urbs[i]->transfer_buffer == NULL)
1288: goto allocfail;
1289: usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
1290: usb->video_urbs[i]->transfer_buffer, v_urb_len,
1291: go7007_usb_read_video_pipe_complete, go);
1292: }
1293:
1294: /* Allocate the URBs and buffers for receiving the audio stream */
1295: if ((board->flags & GO7007_USB_EZUSB) &&
1296: (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) {
1297: if (!usb->usbdev->ep_in[8])
1298: goto allocfail;
1299: for (i = 0; i < 8; ++i) {
1300: usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
1301: if (usb->audio_urbs[i] == NULL)
1302: goto allocfail;
1303: usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,
1304: GFP_KERNEL);
1305: if (usb->audio_urbs[i]->transfer_buffer == NULL)
1306: goto allocfail;
1307: usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,
1308: usb_rcvbulkpipe(usb->usbdev, 8),
1309: usb->audio_urbs[i]->transfer_buffer, 4096,
1310: go7007_usb_read_audio_pipe_complete, go);
1311: }
1312: }
1313:
1314: /* Do any final GO7007 initialization, then register the
1315: * V4L2 and ALSA interfaces */
1316: if (go7007_register_encoder(go, num_i2c_devs) < 0)
1317: goto allocfail;
1318:
1319: go->status = STATUS_ONLINE;
1320: return 0;
1321:
1322: allocfail:
1323: go7007_usb_release(go);
1324: kfree(go);
1325: return -ENOMEM;
1326: }
SourceFile:drivers/media/usb/go7007/go7007-usb.c]
|
| 506/2 |
2026/07/30 13:36 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 61998
output: 54
thoughts: 118
Thoughts: **Analyzing the GO7007 USB Probe Function**
Okay, let's break this down. My initial observation is that `go7007_usb_probe` is adding the I2C adapter using `i2c_add_adapter(&go->i2c_adapter)` around line 1172. That's a key part of the device setup. Now, I see that right after that, at line 1271, we have a crucial check: `if (!usb->usbdev->ep_in[6]) goto allocfail;`. Essentially, we're verifying the existence of the input endpoint. If that check fails, the code jumps to `allocfail`.
And if we hit `allocfail`, the function calls `go7007_usb_release(go)` *and* `kfree(go)`. The driver's cleaning up its resources, which is sensible. Before I continue, I really should examine what is happening inside `go7007_usb_release`, to ensure the teardown is properly handled.
|
| 507/2 |
2026/07/30 13:36 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/usb/go7007/go7007-usb.c Name:go7007_usb_release]
Results: map[SourceCode: 896: static void go7007_usb_release(struct go7007 *go)
897: {
898: struct go7007_usb *usb = go->hpi_context;
899: struct urb *vurb, *aurb;
900: int i;
901:
902: if (usb->intr_urb) {
903: usb_kill_urb(usb->intr_urb);
904: kfree(usb->intr_urb->transfer_buffer);
905: usb_free_urb(usb->intr_urb);
906: }
907:
908: /* Free USB-related structs */
909: for (i = 0; i < 8; ++i) {
910: vurb = usb->video_urbs[i];
911: if (vurb) {
912: usb_kill_urb(vurb);
913: kfree(vurb->transfer_buffer);
914: usb_free_urb(vurb);
915: }
916: aurb = usb->audio_urbs[i];
917: if (aurb) {
918: usb_kill_urb(aurb);
919: kfree(aurb->transfer_buffer);
920: usb_free_urb(aurb);
921: }
922: }
923:
924: kfree(go->hpi_context);
925: }
SourceFile:drivers/media/usb/go7007/go7007-usb.c]
|
| 508/2 |
2026/07/30 13:36 |
llm |
crash-repro-finder |
0m
Model:
Tokens:
input: 62882
output: 54
thoughts: 288
Thoughts: **The Eureka Moment!**
Yes! I've got it! The `go7007_usb_release` function *doesn't* call `i2c_del_adapter`! It just frees the URBs and the `go->hpi_context`. And then, right after, `go7007_usb_probe` goes and calls `kfree(go)`! The crucial thing is that `go->i2c_adapter` is *embedded* within the `struct go7007` itself! Meaning it's being freed while still registered in the I2C subsystem! That's the bug, plain and simple!
Now, why didn't my reproducer hit this consistently? I need to understand that. Let's look at `go7007_boot_encoder`. That's called *before* `i2c_add_adapter`, isn't it?
```c
/* Boot the GO7007 */
if (go7007_boot_encoder(go, go->board_info->flags &
GO7007_BOARD_USE_ONBOARD_I2C) < 0)
goto allocfail;
```
Ah, here we go! If `go7007_boot_encoder` fails, the code jumps to `allocfail` *before* `i2c_add_adapter` gets called! Therefore, to trigger the bug, we *must* ensure that `go7007_boot_encoder` succeeds. I need to dive deeper into `go7007_boot_encoder` now, and understand what conditions might cause it to fail. That's the key to reliable reproduction!
|
| 509/2 |
2026/07/30 13:36 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/media/usb/go7007/go7007-driver.c Name:go7007_boot_encoder]
Results: map[SourceCode: 121: /*
122: * Boot the encoder and register the I2C adapter if requested. Do the
123: * minimum initialization necessary, since the board-specific code may
124: * still need to probe the board ID.
125: *
126: * Must NOT be called with the hw_lock held.
127: */
128: int go7007_boot_encoder(struct go7007 *go, int init_i2c)
129: {
130: int ret;
131:
132: mutex_lock(&go->hw_lock);
133: ret = go7007_load_encoder(go);
134: mutex_unlock(&go->hw_lock);
135: if (ret < 0)
136: return -1;
137: if (!init_i2c)
138: return 0;
139: if (go7007_i2c_init(go) < 0)
140: return -1;
141: go->i2c_adapter_online = 1;
142: return 0;
143: }
SourceFile:drivers/media/usb/go7007/go7007-driver.c]
|