Contents
mm/ (12 functions) — 0 real, 13 FP
mm/kasan/ (1 function) — 0 real, 5 FP
mm/ (12 functions) — 0 real, 13 FP
copy_folio_from_user() — memory.c FP
get_bitmap() — mempolicy.c FP
do_pages_stat() — migrate.c FP
shrinker_debugfs_scan_write() — shrinker_debug.c FP
mfill_copy_folio_locked() — userfaultfd.c FP
mfill_copy_folio_retry() — userfaultfd.c FP
memdup_user() — util.c FP
memdup_user_nul() — util.c FP
vmemdup_user() — util.c FP
lru_gen_seq_write() — vmscan.c FP
Summary
| Function | File | Assessment | Confidence | Real | FP | Unanalyzed |
|---|---|---|---|---|---|---|
| mm/ — 12 functions, 0 real, 13 FP | ||||||
| pin_longterm_test_read() | mm/gup_test.c | FP | high | 0 | 1 | 0 |
| split_huge_pages_write() | mm/huge_memory.c | FP | high | 0 | 1 | 0 |
| mm/kasan/ — 1 function, 0 real, 5 FP | ||||||
| copy_user_test_oob() | mm/kasan/kasan_test_c.c | FP | high | 0 | 5 | 0 |
| mm/ — 12 functions, 0 real, 13 FP | ||||||
| copy_folio_from_user() | mm/memory.c | FP | high | 0 | 1 | 0 |
| get_bitmap() | mm/mempolicy.c | FP | high | 0 | 1 | 0 |
| do_pages_stat() | mm/migrate.c | FP | high | 0 | 2 | 0 |
| shrinker_debugfs_scan_write() | mm/shrinker_debug.c | FP | high | 0 | 1 | 0 |
| mfill_copy_folio_locked() | mm/userfaultfd.c | FP | high | 0 | 1 | 0 |
| mfill_copy_folio_retry() | mm/userfaultfd.c | FP | high | 0 | 1 | 0 |
| memdup_user() | mm/util.c | FP | high | 0 | 1 | 0 |
| memdup_user_nul() | mm/util.c | FP | high | 0 | 1 | 0 |
| vmemdup_user() | mm/util.c | FP | high | 0 | 1 | 0 |
| lru_gen_seq_write() | mm/vmscan.c | FP | high | 0 | 1 | 0 |
Function Details
pin_longterm_test_read() — mm/gup_test.c FP confidence=high
The static analyzer incorrectly flagged PAGE_SIZE as a user-controlled size argument to copy_to_user(). PAGE_SIZE is a kernel-internal constant (defined at compile time or boot time based on architecture), not derived from any user-supplied or server-supplied data. The taint source listed ('copy_to_user() line 308') is the sink itself, not a genuine external taint source. The loop iterates over kernel-pinned pages using the kernel-controlled counter pin_longterm_test_nr_pages, and copies exactly PAGE_SIZE bytes per page — all kernel-internal values. The user_addr is read from userspace via copy_from_user, but it is used only as the destination pointer in copy_to_user, not as a size argument.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_to_user() line 308 |
| Taint snippet | ret = copy_to_user((void __user *)(unsigned long)user_addr, addr, |
| Tainted var | PAGE_SIZE |
| Unvalidated size | copy_to_user() arg 2 line 308 — size PAGE_SIZE |
| Sink snippet | ret = copy_to_user((void __user *)(unsigned long)user_addr, addr, |
| Possibly guarded | no |
Dismissed: PAGE_SIZE is a kernel compile-time or boot-time constant — it is not user-supplied or server-supplied in any way. The scanner appears to have confused the taint source: it lists 'copy_to_user()' itself as both source and sink, which is a clear false positive. The size argument to copy_to_user() is PAGE_SIZE, which is entirely kernel-controlled. No counterexample can be constructed where a user-controlled value reaches the size argument, because the size argument is PAGE_SIZE, a kernel constant. This is a straightforward false positive from the static analyzer misidentifying the taint source.
split_huge_pages_write() — mm/huge_memory.c FP confidence=high
The flagged copy_from_user call uses min_t(size_t, count, MAX_INPUT_BUF_SZ) as the size argument, which clamps the user-supplied count to at most MAX_INPUT_BUF_SZ bytes. The destination buffer input_buf is declared as char input_buf[MAX_INPUT_BUF_SZ] on the stack, so the copy can never exceed the buffer's capacity. The scanner incorrectly treats the result of min_t() as unvalidated because 'count' is user-controlled, but the min_t() call is itself the validation/clamping operation. No counterexample exists: any value of count, however large, results in a copy of at most MAX_INPUT_BUF_SZ bytes into a buffer of exactly MAX_INPUT_BUF_SZ bytes.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 4858 |
| Taint snippet | if (copy_from_user(input_buf, buf, min_t(size_t, count, MAX_INPUT_BUF_SZ))) |
| Tainted var | min_t(size_t, count, MAX_INPUT_BUF_SZ) |
| Unvalidated size | copy_from_user() arg 2 line 4858 — size min_t(size_t, count, MAX_INPUT_BUF_SZ) |
| Sink snippet | if (copy_from_user(input_buf, buf, min_t(size_t, count, MAX_INPUT_BUF_SZ))) |
| Possibly guarded | no |
Dismissed: The size argument is min_t(size_t, count, MAX_INPUT_BUF_SZ), which mathematically caps the copy length at MAX_INPUT_BUF_SZ regardless of what the user provides. The destination buffer input_buf is exactly MAX_INPUT_BUF_SZ bytes, so the copy is always in bounds. No counterexample can be constructed where the guard fails to prevent overflow. This is a classic false positive from taint analysis that does not model the semantics of min_t() as a bounds clamp.
copy_user_test_oob() — mm/kasan/kasan_test_c.c FP confidence=high
This is a KASAN test function (kasan_test_c.c). Its entire purpose is to intentionally trigger out-of-bounds accesses to verify that KASAN detects them. The 'size' variable is computed locally as '128 - KASAN_GRANULE_SIZE' (a compile-time constant expression), not read from any user-supplied or server-supplied source. The scanner incorrectly identifies the return value of copy_from_user/copy_to_user as a taint source and propagates it to subsequent uses of 'size', but 'size' is never modified by those return values — it is a locally-defined constant. All flagged uses of 'size + 1' are deliberate OOB accesses wrapped in KUNIT_EXPECT_KASAN_FAIL macros, which expect and require the KASAN failure. This is intentional test code, not a production security bug.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 2181 |
| Taint snippet | unused = copy_from_user(kmem, usermem, size + 1)); |
| Tainted var | size + 1 |
| Unvalidated size | copy_from_user() arg 2 line 2181 — size size + 1 |
| Sink snippet | unused = copy_from_user(kmem, usermem, size + 1)); |
| Possibly guarded | no |
Dismissed: size = 128 - KASAN_GRANULE_SIZE is a kernel-internal compile-time constant, not server/user supplied. The OOB access is intentional and wrapped in KUNIT_EXPECT_KASAN_FAIL to verify KASAN detection. False positive.
Finding #2 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_to_user() line 2183 |
| Taint snippet | unused = copy_to_user(usermem, kmem, size + 1)); |
| Tainted var | size + 1 |
| Unvalidated size | copy_to_user() arg 2 line 2183 — size size + 1 |
| Sink snippet | unused = copy_to_user(usermem, kmem, size + 1)); |
| Possibly guarded | no |
Dismissed: Same as finding #1. size is a locally-computed constant. The intentional OOB write to kmem via copy_to_user is wrapped in KUNIT_EXPECT_KASAN_FAIL_READ to verify KASAN detection. False positive.
Finding #3 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | __copy_from_user() line 2185 |
| Taint snippet | unused = __copy_from_user(kmem, usermem, size + 1)); |
| Tainted var | size + 1 |
| Unvalidated size | __copy_from_user() arg 2 line 2185 — size size + 1 |
| Sink snippet | unused = __copy_from_user(kmem, usermem, size + 1)); |
| Possibly guarded | no |
Dismissed: Same as finding #1. Intentional OOB in KASAN test code. False positive.
Finding #4 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | __copy_to_user() line 2187 |
| Taint snippet | unused = __copy_to_user(usermem, kmem, size + 1)); |
| Tainted var | size + 1 |
| Unvalidated size | __copy_to_user() arg 2 line 2187 — size size + 1 |
| Sink snippet | unused = __copy_to_user(usermem, kmem, size + 1)); |
| Possibly guarded | no |
Dismissed: Same as finding #1. Intentional OOB in KASAN test code. False positive.
Finding #5 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_to_user() line 2198 |
| Taint snippet | KUNIT_EXPECT_EQ(test, copy_to_user(usermem, kmem, size), 0); |
| Tainted var | size |
| Unvalidated size | copy_to_user() arg 2 line 2198 — size size |
| Sink snippet | KUNIT_EXPECT_EQ(test, copy_to_user(usermem, kmem, size), 0); |
| Possibly guarded | no |
Dismissed: This use of 'size' (without +1) copies exactly size bytes into a size-byte kmem buffer — this is a valid, correctly-sized copy used to prepare userspace memory for the subsequent strncpy_from_user OOB test. The scanner incorrectly tracks a taint through copy_to_user's return value back to 'size', but 'size' is never assigned from copy_to_user. False positive.
copy_folio_from_user() — mm/memory.c FP confidence=high
PAGE_SIZE is a kernel-internal compile-time constant (or arch-defined macro), not a value read from a user/server-supplied buffer. The taint source listed is copy_from_user() itself on line 7500, but the scanner has misidentified PAGE_SIZE as the tainted value flowing into the size argument of copy_from_user(). PAGE_SIZE is a fixed kernel constant representing the system page size (e.g., 4096 on x86). It is never user-controlled or server-supplied. The destination buffer 'kaddr' is a kernel mapping of exactly one page (via kmap_local_page), so copying PAGE_SIZE bytes into it is precisely correct. The loop iterates nr_pages times, derived from folio_nr_pages() which is a kernel-internal property of the folio, not externally supplied. There is no missing validation here.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 7500 |
| Taint snippet | rc = copy_from_user(kaddr, usr_src + i * PAGE_SIZE, PAGE_SIZE); |
| Tainted var | PAGE_SIZE |
| Unvalidated size | copy_from_user() arg 2 line 7500 — size PAGE_SIZE |
| Sink snippet | rc = copy_from_user(kaddr, usr_src + i * PAGE_SIZE, PAGE_SIZE); |
| Possibly guarded | no |
Dismissed: PAGE_SIZE is a kernel-internal constant (architecture-defined, set at boot or compile time), not a user-supplied or server-supplied value. The scanner incorrectly identified it as tainted because copy_from_user() was listed as a taint source and PAGE_SIZE appears as the size argument to another copy_from_user() call. However, PAGE_SIZE does not derive from any user-provided data — it is a fixed system constant. The destination buffer kaddr is a kmap of one page, exactly PAGE_SIZE bytes, so the copy is always within bounds. No counterexample can be constructed because PAGE_SIZE is not variable at runtime in a user-controlled way. This is a textbook false positive from the static analyzer confusing a kernel constant with tainted data.
get_bitmap() — mm/mempolicy.c FP confidence=high
The tainted size (nlongs * sizeof(unsigned long)) is user-controlled via maxnode, but get_nodes() enforces 'maxnode > PAGE_SIZE*BITS_PER_BYTE => -EINVAL' before calling get_bitmap(). At call site line 1677, bits is further bounded by min_t(..., BITS_PER_LONG) so nlongs=1 and mask=&t (one ulong). At call site line 1690, the while-loop reduces maxnode to <= MAX_NUMNODES before the call, so copy_from_user's size is bounded to BITS_TO_LONGS(MAX_NUMNODES)*sizeof(ulong), which exactly fits nodes_addr(*nodes). No counterexample can pass all guards and still cause OOB.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 1645 |
| Taint snippet | ret = copy_from_user(mask, nmask, |
| Tainted var | nlongs * sizeof(unsigned long) |
| Unvalidated size | copy_from_user() arg 2 line 1645 — size nlongs * sizeof(unsigned long) |
| Sink snippet | ret = copy_from_user(mask, nmask, |
| Possibly guarded | no |
Dismissed: At call site line 1677: bits=min_t(maxnode,BITS_PER_LONG)<=BITS_PER_LONG, so nlongs=1, mask=&t (one ulong on stack) — safe. At call site line 1690: the while loop runs while maxnode>MAX_NUMNODES and subtracts bits each iteration, so upon exit maxnode<=MAX_NUMNODES; thus nlongs<=BITS_TO_LONGS(MAX_NUMNODES) which is exactly the size of nodemask_t — safe. No counterexample exists that passes both the PAGE_SIZE*BITS_PER_BYTE guard and the while-loop reduction and still overflows the destination buffer. False positive.
do_pages_stat() — mm/migrate.c FP confidence=high
chunk_nr is computed as min(nr_pages, DO_PAGES_STAT_CHUNK_NR) where DO_PAGES_STAT_CHUNK_NR=16. Regardless of the user-supplied nr_pages value, chunk_nr is always ≤ 16, making the copy sizes exactly fit within the stack-allocated chunk_pages[16] and chunk_status[16] arrays. The scanner's taint analysis propagated the user-controlled nature of nr_pages through the min() expression but did not account for the clamping effect of min().
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 2526 |
| Taint snippet | if (copy_from_user(chunk_pages, pages + chunk_offset, |
| Tainted var | chunk_nr * sizeof(*chunk_pages) |
| Unvalidated size | copy_from_user() arg 2 line 2526 — size chunk_nr * sizeof(*chunk_pages) |
| Sink snippet | if (copy_from_user(chunk_pages, pages + chunk_offset, |
| Possibly guarded | no |
Dismissed: chunk_nr = min(nr_pages, 16UL) is always ≤ 16. The destination buffer chunk_pages has exactly 16 elements. chunk_nr * sizeof(*chunk_pages) ≤ sizeof(chunk_pages). No counterexample can be constructed: any nr_pages value yields chunk_nr ≤ 16, which never exceeds the buffer. False positive.
Finding #2 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_to_user() line 2533 |
| Taint snippet | if (copy_to_user(status + chunk_offset, chunk_status, |
| Tainted var | chunk_nr * sizeof(*status) |
| Unvalidated size | copy_to_user() arg 2 line 2533 — size chunk_nr * sizeof(*status) |
| Sink snippet | if (copy_to_user(status + chunk_offset, chunk_status, |
| Possibly guarded | no |
Dismissed: Same reasoning as finding #1. chunk_nr ≤ 16 and chunk_status has 16 elements, so chunk_nr * sizeof(*status) ≤ sizeof(chunk_status). The copy to userspace (status + chunk_offset) is a write to user memory, not a kernel buffer overflow. No counterexample exists. False positive.
shrinker_debugfs_scan_write() — mm/shrinker_debug.c FP confidence=high
The taint source flagged by the scanner is copy_from_user() itself, which populates 'read_len' — but read_len is NOT derived from user data. It is computed on line 114 as min(size, sizeof(kbuf) - 1), where sizeof(kbuf) is the compile-time size of the 72-byte stack buffer. The min() call strictly clamps read_len to at most sizeof(kbuf)-1 = 71, which is always less than the destination buffer size of 72. No counterexample exists where read_len could exceed the buffer capacity. The scanner is confused because copy_from_user() is both the 'taint source' (the data read) and the 'sink' (the call itself), and it is misidentifying read_len as user-controlled when read_len is actually a kernel-internal clamped value.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 115 |
| Taint snippet | if (copy_from_user(kbuf, buf, read_len)) |
| Tainted var | read_len |
| Unvalidated size | copy_from_user() arg 2 line 115 — size read_len |
| Sink snippet | if (copy_from_user(kbuf, buf, read_len)) |
| Possibly guarded | no |
Dismissed: read_len = min(size, sizeof(kbuf) - 1) clamps the copy length to at most 71 bytes, which is strictly less than the 72-byte kbuf. No counterexample is possible: any value of user-supplied 'size' results in read_len <= 71 < 72, so copy_from_user() cannot overflow kbuf. The scanner incorrectly treats read_len as tainted because it appears in the copy_from_user call, but the value itself is a kernel-computed minimum, not user-supplied.
mfill_copy_folio_locked() — mm/userfaultfd.c FP confidence=high
The static analyzer has incorrectly flagged PAGE_SIZE as a user-controlled/tainted value. PAGE_SIZE is a kernel compile-time constant (or boot-time constant), not derived from any user-supplied or server-supplied data. The copy_from_user() call copies exactly one page worth of data from a user-space source address into a kernel-allocated folio page, which is always PAGE_SIZE bytes. The destination buffer (kmap_local_folio result) is also PAGE_SIZE bytes. There is no missing bounds check here — copying PAGE_SIZE bytes into a PAGE_SIZE kernel buffer is inherently safe in terms of destination buffer overflow. The taint propagation from copy_from_user() return value to PAGE_SIZE is a spurious analyzer inference; copy_from_user() returns the number of bytes NOT copied, not a size value that feeds back into the size argument.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 452 |
| Taint snippet | ret = copy_from_user(kaddr, (const void __user *) src_addr, |
| Tainted var | PAGE_SIZE |
| Unvalidated size | copy_from_user() arg 2 line 452 — size PAGE_SIZE |
| Sink snippet | ret = copy_from_user(kaddr, (const void __user *) src_addr, |
| Possibly guarded | no |
Dismissed: PAGE_SIZE is a kernel-internal constant, not user-supplied or server-supplied data. The analyzer appears to have confused the taint source: copy_from_user() returns the number of bytes NOT copied (stored in 'ret'), which is then checked (if ret → return -EFAULT). The size argument to copy_from_user() is PAGE_SIZE, a compile-time/boot-time constant that cannot be influenced by userspace. The destination buffer from kmap_local_folio is always exactly PAGE_SIZE bytes for a single folio page. No counterexample can be constructed where PAGE_SIZE exceeds the destination buffer size, because they are identical by construction. This is a false positive.
mfill_copy_folio_retry() — mm/userfaultfd.c FP confidence=high
The flagged 'tainted variable' is PAGE_SIZE, which is a kernel-internal compile-time constant (typically 4096 bytes on x86). It is not derived from user input, server responses, or any runtime variable. The static analysis tool incorrectly identified copy_from_user() itself as a taint source and then flagged the size argument in the very same call, confusing the function's return value (bytes not copied) with its arguments. PAGE_SIZE is always a fixed, architecture-defined constant and cannot be influenced by user-space or a network peer. The destination buffer kaddr is obtained from kmap_local_folio(folio, 0), which maps exactly one page (PAGE_SIZE bytes). The copy is therefore correctly sized.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 540 |
| Taint snippet | err = copy_from_user(kaddr, (const void __user *) src_addr, PAGE_SIZE); |
| Tainted var | PAGE_SIZE |
| Unvalidated size | copy_from_user() arg 2 line 540 — size PAGE_SIZE |
| Sink snippet | err = copy_from_user(kaddr, (const void __user *) src_addr, PAGE_SIZE); |
| Possibly guarded | no |
Dismissed: PAGE_SIZE is a kernel compile-time constant, not a user-supplied or server-supplied value. The scanner appears to have treated the return value of copy_from_user() (bytes not copied) as tainting the size argument, which is a false-positive artifact of the analysis. kmap_local_folio maps exactly PAGE_SIZE bytes, and copy_from_user is called with PAGE_SIZE as the size, making the operation correctly bounded. No counterexample exists where PAGE_SIZE could be manipulated to cause OOB access.
memdup_user() — mm/util.c FP confidence=high
memdup_user() is a standard kernel utility that allocates exactly 'len' bytes and then copies exactly 'len' bytes from userspace. Because the allocation size and copy size are identical, there is no buffer overflow risk within this function. The scanner incorrectly attributes the taint source to copy_from_user()'s return value rather than recognizing 'len' is a caller-supplied parameter. Validation of 'len' range (e.g., against a maximum) is the caller's responsibility, not this utility's. The function correctly handles allocation failure and copy failure.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 225 |
| Taint snippet | if (copy_from_user(p, src, len)) { |
| Tainted var | len |
| Unvalidated size | copy_from_user() arg 2 line 225 — size len |
| Sink snippet | if (copy_from_user(p, src, len)) { |
| Possibly guarded | no |
Dismissed: The scanner misidentifies the taint source: 'len' is a function parameter, not something read by copy_from_user(). More importantly, the destination buffer 'p' is allocated with exactly 'len' bytes (via kmem_buckets_alloc_track_caller), so copy_from_user() with size 'len' cannot overflow 'p'. Allocation failure (returning NULL) is handled before the copy. No counterexample can be constructed where len causes OOB within this function because allocation and copy sizes are always equal. Any range validation of len is a caller-level concern. This is a false positive.
memdup_user_nul() — mm/util.c FP confidence=high
This is the generic memdup_user_nul() utility in lib/util.c (or similar). The function allocates len+1 bytes and copies len bytes from userspace. The allocation is sized to exactly len+1, so the copy of len bytes fits perfectly — there is no OOB write. The scanner confused itself by flagging 'len' as a tainted size argument, but the destination buffer p is allocated as kmem_buckets_alloc_track_caller(user_buckets, len+1, ...), which is always >= len+1 bytes. The copy_from_user call copies exactly len bytes into a buffer of len+1 bytes, which is safe by construction. The callers of memdup_user_nul() are responsible for validating len before calling this function; within this function, the allocation and copy are consistently sized.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 307 |
| Taint snippet | if (copy_from_user(p, src, len)) { |
| Tainted var | len |
| Unvalidated size | copy_from_user() arg 2 line 307 — size len |
| Sink snippet | if (copy_from_user(p, src, len)) { |
| Possibly guarded | no |
Dismissed: The taint source is copy_from_user() itself, which the scanner is treating as introducing a tainted 'len'. However, 'len' is a parameter passed to memdup_user_nul() and the function's only use of 'len' is: (1) allocate len+1 bytes, and (2) copy len bytes into that allocation. The destination buffer is always exactly large enough for the copy — p has len+1 bytes and copy_from_user copies len bytes. No counterexample is possible: any value of len results in an allocation of at least len+1 bytes, making the copy always in-bounds. This is a classic false positive where the static analyzer confuses the size parameter with being unvalidated against the destination, but the destination is sized from the same parameter. Caller responsibility for upper-bounding len is outside the scope of this function.
vmemdup_user() — mm/util.c FP confidence=high
vmemdup_user() is a generic utility that allocates exactly 'len' bytes and copies exactly 'len' bytes from userspace. Since the allocation size and copy size are identical, there is no buffer overflow risk within this function. The scanner flagged 'len' as user-controlled, but the destination buffer is always sized to accommodate the copy. Validation of 'len' against application-specific upper bounds is the responsibility of callers, not this utility.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 251 |
| Taint snippet | if (copy_from_user(p, src, len)) { |
| Tainted var | len |
| Unvalidated size | copy_from_user() arg 2 line 251 — size len |
| Sink snippet | if (copy_from_user(p, src, len)) { |
| Possibly guarded | no |
Dismissed: The allocation `kmem_buckets_valloc(user_buckets, len, GFP_USER)` uses the same `len` as the `copy_from_user(p, src, len)` call. The destination buffer is exactly `len` bytes, so the copy cannot overflow it. The NULL check after allocation handles the case where `len` is too large for the allocator. No counterexample exists where the copy overflows the allocated buffer, because they share the same size expression. This is a false positive: the scanner sees `len` is user-tainted but misses that the allocation is also sized by `len`.
lru_gen_seq_write() — mm/vmscan.c FP confidence=high
This is a standard sysfs/procfs-style write handler. The 'len' parameter is the kernel's own 'size_t len' argument to the file_operations->write callback, which comes from the VFS layer after the user's write(2) syscall. It represents how many bytes the user wants to write — it is NOT a value read from user memory. The allocation is 'kvmalloc(len + 1, GFP_KERNEL)' which allocates exactly len+1 bytes, and then 'copy_from_user(buf, src, len)' copies exactly len bytes into that buffer. The destination buffer is always large enough for the copy. The scanner is confused because 'len' is a parameter that relates to user-provided data, but it is a kernel ABI value (the write syscall's count argument) passed by the VFS, not something read from user memory with get_user or copy_from_user. There is no OOB risk here.
Finding #1 — Category G2 — false positive
| Category | Cat G2 — unvalidated size argument to copy_from/to_user |
|---|---|
| Taint source | copy_from_user() line 5679 |
| Taint snippet | if (copy_from_user(buf, src, len)) { |
| Tainted var | len |
| Unvalidated size | copy_from_user() arg 2 line 5679 — size len |
| Sink snippet | if (copy_from_user(buf, src, len)) { |
| Possibly guarded | no |
Dismissed: The 'len' parameter is the VFS-supplied write count from the write(2) syscall, not a value read from user memory. The buffer is allocated as kvmalloc(len + 1) and copy_from_user copies exactly len bytes, so the destination is always sufficient. No counterexample exists: any value of len results in a buffer of len+1 bytes, so copy_from_user(buf, src, len) always stays within bounds. This is a textbook false positive for this category of static analysis finding.