Bounds Checker Report — 20260819_082622_fs_smb_client

Date: 2026-08-19 08:28:26 Model: claude-sonnet-4-6 Source: fs/smb/client Files: 91 Stage 1: 259 findings (Cat A: 24  |  Cat B: 58  |  Cat C: 19  |  Cat E: 126  |  Cat F: 20  |  Cat G2: 1  |  Cat H: 11) Stage 2: 65 real  |  167 FP  |  27 unanalyzed Kernel: v7.2-948-gb410daca23c4 Branch: work/smb2-symlink-ctx-fix
1 local commit(s) since origin/master
  1. b410daca23c4 smb: client: fix remaining infinite-loop and FORTIFY trap in symlink_data()

Contents

fs/smb/client/ (67 functions) — 65 real, 167 FP
open_cached_dir() — cached_dir.c FP build_sec_desc() — cifsacl.c FP id_mode_to_cifs_acl() — cifsacl.c FP parse_dacl() — cifsacl.c MIXED parse_sec_desc() — cifsacl.c FP replace_sids_and_copy_aces() — cifsacl.c FP set_chmod_dacl() — cifsacl.c FP validate_dacl() — cifsacl.c FP CIFSFindFirst() — cifssmb.c BUG CIFSFindNext() — cifssmb.c BUG CIFSGetExtAttr() — cifssmb.c BUG CIFSGetSrvInodeNumber() — cifssmb.c BUG CIFSPOSIXCreate() — cifssmb.c VALIDATE CIFSSMBPosixLock() — cifssmb.c BUG CIFSSMBQAllEAs() — cifssmb.c MIXED CIFSSMBQFSAttributeInfo() — cifssmb.c BUG CIFSSMBQFSDeviceInfo() — cifssmb.c BUG CIFSSMBQFSInfo() — cifssmb.c BUG CIFSSMBQFSPosixInfo() — cifssmb.c VALIDATE CIFSSMBQFSUnixInfo() — cifssmb.c BUG CIFSSMBRead() — cifssmb.c MIXED CIFSSMBUnixQuerySymLink() — cifssmb.c MIXED SMBOldQFSInfo() — cifssmb.c BUG cifs_create_reparse_inode() — cifssmb.c MIXED cifs_do_get_acl() — cifssmb.c MIXED cifs_query_reparse_point() — cifssmb.c BUG cifs_to_posix_acl() — cifssmb.c FP parse_dfs_referrals() — misc.c FP cnvrtDosUnixTm() — netmisc.c FP mknod_wsl() — reparse.c FP parse_reparse_native_symlink() — reparse.c FP parse_reparse_nfs() — reparse.c FP parse_reparse_wsl_symlink() — reparse.c FP map_smb_to_linux_error() — smb1maperror.c FP is_valid_oplock_break() — smb1misc.c BUG cifs_query_path_info() — smb1ops.c ERROR coalesce_t2() — smb1transport.c BUG smb2_parse_symlink_response() — smb2file.c FP check_wsl_eas() — smb2inode.c FP parse_posix_sids() — smb2inode.c FP reparse_buf_ptr() — smb2inode.c BUG smb2_compound_op() — smb2inode.c FP __smb2_calc_size() — smb2misc.c VALIDATE smb2_check_message() — smb2misc.c FP smb2_tcon_find_pending_open_lease() — smb2misc.c VALIDATE smb2_tcon_has_lease() — smb2misc.c BUG crypt_message() — smb2ops.c FP move_smb2_ea_to_cifs() — smb2ops.c FP parse_server_interfaces() — smb2ops.c FP receive_encrypted_standard() — smb2ops.c BUG smb2_query_eas() — smb2ops.c FP smb3_enum_snapshots() — smb2ops.c FP smb3_fiemap() — smb2ops.c FP smb3_simple_fallocate_range() — smb2ops.c FP SMB2_QFS_attr() — smb2pdu.c FP __smb2_plain_req_init() — smb2pdu.c FP decode_compress_ctx() — smb2pdu.c FP fill_small_buf() — smb2pdu.c FP parse_posix_ctxt() — smb2pdu.c FP posix_info_parse() — smb2pdu.c BUG query_info() — smb2pdu.c FP smb2_parse_contexts() — smb2pdu.c FP smb311_decode_neg_context() — smb2pdu.c FP smb2_calc_signature() — smb2transport.c FP smb2_seq_num_into_buf() — smb2transport.c FP smb3_calc_signature() — smb2transport.c FP __release_mid() — transport.c FP

Summary

FunctionFileAssessmentConfidenceRealFPUnanalyzed
fs/smb/client/ — 67 functions, 65 real, 167 FP
open_cached_dir()fs/smb/client/cached_dir.cFPhigh010
build_sec_desc()fs/smb/client/cifsacl.cFPhigh0220
id_mode_to_cifs_acl()fs/smb/client/cifsacl.cFPhigh080
parse_dacl()fs/smb/client/cifsacl.cMIXEDmedium210
parse_sec_desc()fs/smb/client/cifsacl.cFPhigh010
replace_sids_and_copy_aces()fs/smb/client/cifsacl.cFPmedium010
set_chmod_dacl()fs/smb/client/cifsacl.cFPmedium010
validate_dacl()fs/smb/client/cifsacl.cFPhigh010
CIFSFindFirst()fs/smb/client/cifssmb.cBUGmedium400
CIFSFindNext()fs/smb/client/cifssmb.cBUGhigh300
CIFSGetExtAttr()fs/smb/client/cifssmb.cBUGhigh200
CIFSGetSrvInodeNumber()fs/smb/client/cifssmb.cBUGhigh100
CIFSPOSIXCreate()fs/smb/client/cifssmb.cVALIDATEmedium500
CIFSSMBPosixLock()fs/smb/client/cifssmb.cBUGhigh700
CIFSSMBQAllEAs()fs/smb/client/cifssmb.cMIXEDmedium380
CIFSSMBQFSAttributeInfo()fs/smb/client/cifssmb.cBUGhigh100
CIFSSMBQFSDeviceInfo()fs/smb/client/cifssmb.cBUGhigh100
CIFSSMBQFSInfo()fs/smb/client/cifssmb.cBUGhigh400
CIFSSMBQFSPosixInfo()fs/smb/client/cifssmb.cVALIDATEmedium900
CIFSSMBQFSUnixInfo()fs/smb/client/cifssmb.cBUGhigh100
CIFSSMBRead()fs/smb/client/cifssmb.cMIXEDhigh110
CIFSSMBUnixQuerySymLink()fs/smb/client/cifssmb.cMIXEDmedium200
SMBOldQFSInfo()fs/smb/client/cifssmb.cBUGhigh400
cifs_create_reparse_inode()fs/smb/client/cifssmb.cMIXEDmedium020
cifs_do_get_acl()fs/smb/client/cifssmb.cMIXEDmedium110
cifs_query_reparse_point()fs/smb/client/cifssmb.cBUGmedium300
cifs_to_posix_acl()fs/smb/client/cifssmb.cFPmedium010
parse_dfs_referrals()fs/smb/client/misc.cFPhigh030
cnvrtDosUnixTm()fs/smb/client/netmisc.cFPhigh010
mknod_wsl()fs/smb/client/reparse.cFPhigh020
parse_reparse_native_symlink()fs/smb/client/reparse.cFPhigh0100
parse_reparse_nfs()fs/smb/client/reparse.cFPhigh010
parse_reparse_wsl_symlink()fs/smb/client/reparse.cFPhigh030
map_smb_to_linux_error()fs/smb/client/smb1maperror.cFPhigh020
is_valid_oplock_break()fs/smb/client/smb1misc.cBUGhigh100
cifs_query_path_info()fs/smb/client/smb1ops.cERRORlow0027
coalesce_t2()fs/smb/client/smb1transport.cBUGhigh300
smb2_parse_symlink_response()fs/smb/client/smb2file.cFPhigh0100
check_wsl_eas()fs/smb/client/smb2inode.cFPhigh0210
parse_posix_sids()fs/smb/client/smb2inode.cFPhigh040
reparse_buf_ptr()fs/smb/client/smb2inode.cBUGhigh100
smb2_compound_op()fs/smb/client/smb2inode.cFPhigh010
__smb2_calc_size()fs/smb/client/smb2misc.cVALIDATEmedium100
smb2_check_message()fs/smb/client/smb2misc.cFPhigh010
smb2_tcon_find_pending_open_lease()fs/smb/client/smb2misc.cVALIDATEmedium100
smb2_tcon_has_lease()fs/smb/client/smb2misc.cBUGmedium100
crypt_message()fs/smb/client/smb2ops.cFPhigh010
move_smb2_ea_to_cifs()fs/smb/client/smb2ops.cFPhigh020
parse_server_interfaces()fs/smb/client/smb2ops.cFPhigh010
receive_encrypted_standard()fs/smb/client/smb2ops.cBUGmedium100
smb2_query_eas()fs/smb/client/smb2ops.cFPhigh080
smb3_enum_snapshots()fs/smb/client/smb2ops.cFPhigh010
smb3_fiemap()fs/smb/client/smb2ops.cFPhigh010
smb3_simple_fallocate_range()fs/smb/client/smb2ops.cFPhigh010
SMB2_QFS_attr()fs/smb/client/smb2pdu.cFPhigh050
__smb2_plain_req_init()fs/smb/client/smb2pdu.cFPhigh010
decode_compress_ctx()fs/smb/client/smb2pdu.cFPhigh010
fill_small_buf()fs/smb/client/smb2pdu.cFPhigh010
parse_posix_ctxt()fs/smb/client/smb2pdu.cFPhigh040
posix_info_parse()fs/smb/client/smb2pdu.cBUGhigh200
query_info()fs/smb/client/smb2pdu.cFPhigh010
smb2_parse_contexts()fs/smb/client/smb2pdu.cFPhigh090
smb311_decode_neg_context()fs/smb/client/smb2pdu.cFPhigh090
smb2_calc_signature()fs/smb/client/smb2transport.cFPhigh010
smb2_seq_num_into_buf()fs/smb/client/smb2transport.cFPhigh010
smb3_calc_signature()fs/smb/client/smb2transport.cFPhigh010
__release_mid()fs/smb/client/transport.cFPhigh0100

Function Details

open_cached_dir() — fs/smb/client/cached_dir.c FP confidence=high

The flagged call to smb2_validate_and_copy_iov() is itself the validation function. It internally calls smb2_validate_iov(offset, buffer_length, iov, minbufsize) before computing begin_of_buf and performing memcpy. The smb2_validate_iov() call checks that offset + buffer_length fits within iov->iov_len, ensuring begin_of_buf points into valid memory. The memcpy inside smb2_validate_and_copy_iov() is only reached after that bounds check passes, so the tainted OutputBufferOffset is validated before use.

Finding #1 — Category A — cross-function via smb2_validate_and_copy_iov() — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 371
Taint snippetif (!smb2_validate_and_copy_iov(
Tainted varle16_to_cpu(qi_rsp->OutputBufferOffset)
Call siteline 371 — passes le16_to_cpu(qi_rsp->OutputBufferOffset) to smb2_validate_and_copy_iov()
Call snippetif (!smb2_validate_and_copy_iov(
Sink (in callee)memcpy() line 3868 (arg 1, role=pointer)
Sink snippetmemcpy(data, begin_of_buf, minbufsize);
Possibly guardedno
Dismissed: smb2_validate_and_copy_iov() is a combined validation-and-copy helper: it calls smb2_validate_iov(offset, buffer_length, iov, minbufsize) which verifies that offset + buffer_length does not exceed iov->iov_len before the memcpy is reached. The tainted OutputBufferOffset is the 'offset' parameter; if it is out of range, smb2_validate_iov returns an error and memcpy is never executed. No counterexample can be constructed: any offset that would cause OOB would also cause smb2_validate_iov to fail. This is a false positive — the scanner flagged the internal memcpy inside the validation function itself.

build_sec_desc() — fs/smb/client/cifsacl.c FP confidence=high

build_sec_desc() has solid validation discipline. When dacloffset is non-zero, dacl_offset_valid() verifies the offset is within buffer bounds before dacl_ptr is created, and validate_dacl() performs a complete per-element traversal of all ACEs with bounds checks before any downstream use. All flagged accesses (dacl_ptr->revision, dacl_ptr->num_aces, set_chmod_dacl loop, replace_sids_and_copy_aces loop) occur only after these validators have returned 0. Findings #5-#10 are the validator's own internal logic. Finding #4 misidentifies a u16-returning function assigned to u16 as a 32->16 truncation. | build_sec_desc() has a thorough validation discipline: dacl_offset_valid() confirms the DACL fits within the buffer, and validate_dacl() walks every ACE with per-element bounds checks before any DACL traversal occurs. replace_sids_and_copy_aces() uses structurally identical arithmetic (same base pointer, same per-element size field, same iteration count) as validate_dacl(), so its traversal is already proven safe by the prior validation gate. The call at line 1529 is additionally guarded by `if (dacloffset)`, ensuring dacl_ptr is non-NULL only when fully validated.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Pointer derefdacl_ptr->revision line 1447
Sink snippetdacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION);
Possibly guardedno
Dismissed: dacl_ptr->revision at line 1447 is only reached when dacloffset != 0, after dacl_offset_valid() and validate_dacl() both pass. validate_dacl() checks end_of_acl >= (char*)pdacl + sizeof(struct smb_acl), which covers the revision field. No counterexample can be constructed: any dacloffset that passes dacl_offset_valid() places pdacl at least sizeof(struct smb_acl) bytes before end_of_acl.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Pointer derefdacl_ptr->revision line 1467
Sink snippetdacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION);
Possibly guardedno
Dismissed: Same as finding #1 — dacl_ptr->revision at line 1467 in the else branch. Same validation chain (dacl_offset_valid + validate_dacl) protects this access. False positive.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Pointer derefdacl_ptr->num_aces line 1468
Sink snippetndacl_ptr->num_aces = dacl_ptr ? dacl_ptr->num_aces : 0;
Possibly guardedno
Dismissed: dacl_ptr->num_aces at line 1468 is guarded by 'dacl_ptr ? ... : 0', and dacl_ptr is non-null only after dacl_offset_valid() + validate_dacl() pass. num_aces is within sizeof(struct smb_acl) from pdacl base, which validate_dacl() confirms fits in the buffer. False positive.

Finding #4 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele32_to_cpu() line 1529
Taint snippetsize = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
Tainted varsize
Truncationline 1529: 32 → 16-bit u16
Sink snippetsize = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
Possibly guardedno
Dismissed: replace_sids_and_copy_aces() is declared as returning __u16 and the result is assigned to u16 size. There is no 32-to-16 bit truncation here. The scanner incorrectly identified this as a truncation. False positive.

Finding #5 — Category F — cross-function via validate_dacl() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1425 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, end_of_acl);
Loopfor_loop line 875
Sink snippetfor (i = 0; i < num_aces; ++i) {
Possibly guardedyes (heuristic)
Dismissed: validate_dacl() IS the validation function. The for loop at line 875 iterates over ACEs and is the bounds-checking logic itself. Accesses inside the validator are the validation, not vulnerable sinks. False positive.

Finding #6 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1425 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, end_of_acl);
Pointer derefdacl_ptr-> line 885
Sink snippetpace->sid.num_subauth == 0 ||
Possibly guardedyes (heuristic)
Dismissed: pace->sid.num_subauth access at line 885 is inside validate_dacl(), which first checks end_of_dacl - acl_base >= ace_hdr_size before this dereference. This is part of the validation logic. False positive.

Finding #7 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1425 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, end_of_acl);
Pointer derefdacl_ptr-> line 886
Sink snippetpace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) {
Possibly guardedyes (heuristic)
Dismissed: Same as #6 — pace->sid.num_subauth at line 886 is within the same guarded block inside the validator. False positive.

Finding #8 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1425 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, end_of_acl);
Pointer derefdacl_ptr-> line 891
Sink snippetace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth;
Possibly guardedyes (heuristic)
Dismissed: pace->sid.num_subauth at line 891 is used after the bounds check at line 884 confirms ace_hdr_size fits. This is validation logic internal to validate_dacl(). False positive.

Finding #9 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1425 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, end_of_acl);
Pointer derefdacl_ptr-> line 893
Sink snippetle16_to_cpu(pace->size) < ace_size) {
Possibly guardedyes (heuristic)
Dismissed: pace->size at line 893 is read inside validate_dacl() after confirming end_of_dacl - acl_base >= ace_size. Validation logic. False positive.

Finding #10 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1425 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, end_of_acl);
Pointer derefdacl_ptr-> line 898
Sink snippetace_size = le16_to_cpu(pace->size);
Possibly guardedyes (heuristic)
Dismissed: pace->size at line 898 is read inside validate_dacl() after all prior checks in the loop pass. This is validation logic. False positive.

Finding #11 — Category F — cross-function via set_chmod_dacl() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1452 — passes dacl_ptr to set_chmod_dacl()
Call snippetrc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Loopfor_loop line 1266
Sink snippetfor (i = 0; i < src_num_aces; ++i) {
Possibly guardedno
Dismissed: set_chmod_dacl() is called at line 1452 only when pnmode && *pnmode != NO_CHANGE_64. dacl_ptr may be NULL here (no dacloffset check before call), but set_chmod_dacl() handles NULL pdacl at line 1253 ('if (!pdacl || posix)'). When dacl_ptr is non-null, validate_dacl() has already confirmed all ACEs fit within bounds. The loop iterates src_num_aces times with the same arithmetic. No counterexample: validate_dacl ensures the entire DACL including all ACEs fits within end_of_acl. False positive.

Finding #12 — Category E — cross-function via set_chmod_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1452 — passes dacl_ptr to set_chmod_dacl()
Call snippetrc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Pointer derefdacl_ptr-> line 1269
Sink snippetif (!new_aces_set && (pntace->flags & INHERITED_ACE)) {
Possibly guardedno
Dismissed: pntace->flags access in set_chmod_dacl at line 1269 — pntace is computed as acl_base + size where size starts at sizeof(struct smb_acl) and advances by validated ace sizes. validate_dacl() confirmed all ACE accesses are in bounds. False positive.

Finding #13 — Category E — cross-function via set_chmod_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1452 — passes dacl_ptr to set_chmod_dacl()
Call snippetrc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Pointer derefdacl_ptr-> line 1280
Sink snippetif (((compare_sids(&pntace->sid, &sid_unix_NFS_mode) == 0) ||
Possibly guardedno
Dismissed: pntace->sid access in set_chmod_dacl at line 1280. Same argument as #12 — validate_dacl() walked all ACEs including sid fields. False positive.

Finding #14 — Category E — cross-function via set_chmod_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1452 — passes dacl_ptr to set_chmod_dacl()
Call snippetrc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Pointer derefdacl_ptr-> line 1281
Sink snippet(compare_sids(&pntace->sid, pownersid) == 0) ||
Possibly guardedyes (heuristic)
Dismissed: pntace->sid at line 1281 in set_chmod_dacl. Protected by validate_dacl() pre-validation. False positive.

Finding #15 — Category E — cross-function via set_chmod_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1452 — passes dacl_ptr to set_chmod_dacl()
Call snippetrc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Pointer derefdacl_ptr-> line 1282
Sink snippet(compare_sids(&pntace->sid, pgrpsid) == 0) ||
Possibly guardedyes (heuristic)
Dismissed: pntace->sid at line 1282 in set_chmod_dacl. Protected by validate_dacl() pre-validation. False positive.

Finding #16 — Category E — cross-function via set_chmod_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1452 — passes dacl_ptr to set_chmod_dacl()
Call snippetrc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Pointer derefdacl_ptr-> line 1283
Sink snippet(compare_sids(&pntace->sid, &sid_everyone) == 0) ||
Possibly guardedyes (heuristic)
Dismissed: pntace->sid at line 1283 in set_chmod_dacl. Protected by validate_dacl() pre-validation. False positive.

Finding #17 — Category E — cross-function via set_chmod_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1452 — passes dacl_ptr to set_chmod_dacl()
Call snippetrc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Pointer derefdacl_ptr-> line 1284
Sink snippet(compare_sids(&pntace->sid, &sid_authusers) == 0))) {
Possibly guardedyes (heuristic)
Dismissed: pntace->sid at line 1284 in set_chmod_dacl. Protected by validate_dacl() pre-validation. False positive.

Finding #18 — Category E — cross-function via set_chmod_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1452 — passes dacl_ptr to set_chmod_dacl()
Call snippetrc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Pointer derefdacl_ptr-> line 1295
Sink snippetsize += le16_to_cpu(pntace->size);
Possibly guardedyes (heuristic)
Dismissed: pntace->size at line 1295 in set_chmod_dacl. validate_dacl() verified all ace->size values are valid and fit within the DACL. The loop traversal is structurally identical to validate_dacl()'s traversal. False positive.

Finding #19 — Category F — cross-function via replace_sids_and_copy_aces() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1529 — passes dacl_ptr to replace_sids_and_copy_aces()
Call snippetsize = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
Loopfor_loop line 1212
Sink snippetfor (i = 0; i < src_num_aces; ++i) {
Possibly guardedno
Dismissed: replace_sids_and_copy_aces() at line 1529 is called only when dacloffset is non-zero (line 1527 guard), meaning dacl_offset_valid() and validate_dacl() already passed at lines 1419-1427. The loop iterates pdacl->num_aces times with identical arithmetic to validate_dacl(). Container-level validation covers this traversal. No counterexample possible. False positive.

Finding #20 — Category E — cross-function via replace_sids_and_copy_aces() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1529 — passes dacl_ptr to replace_sids_and_copy_aces()
Call snippetsize = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
Pointer derefdacl_ptr-> line 1216
Sink snippetif (pnownersid && compare_sids(&pntace->sid, pownersid) == 0) {
Possibly guardedno
Dismissed: pntace->sid access in replace_sids_and_copy_aces() at line 1216. Same protection as finding #19 — validate_dacl() confirmed all ACE sid accesses are in bounds before this function is called. False positive.

Finding #21 — Category E — cross-function via replace_sids_and_copy_aces() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1529 — passes dacl_ptr to replace_sids_and_copy_aces()
Call snippetsize = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
Pointer derefdacl_ptr-> line 1219
Sink snippet} else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0) {
Possibly guardedyes (heuristic)
Dismissed: dacl_ptr is derived from server-supplied dacloffset, but is fully validated before use: dacl_offset_valid() checks the offset is within the buffer, and validate_dacl() walks all ACEs verifying each ACE's size and SID fit within [dacl_ptr, end_of_acl]. replace_sids_and_copy_aces() is called inside `if (dacloffset)` so dacl_ptr is non-NULL. The traversal in replace_sids_and_copy_aces() at line 1219 accesses pntace->sid, which validate_dacl() already proved is within bounds. No counterexample can be constructed: any ACE whose SID or size would go out of range would have caused validate_dacl() to return an error before reaching line 1529.

Finding #22 — Category E — cross-function via replace_sids_and_copy_aces() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1417
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1529 — passes dacl_ptr to replace_sids_and_copy_aces()
Call snippetsize = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
Pointer derefdacl_ptr-> line 1226
Sink snippetsize += le16_to_cpu(pntace->size);
Possibly guardedno
Dismissed: The sink at line 1226 (`size += le16_to_cpu(pntace->size)`) reads pntace->size from the validated DACL. validate_dacl() has already walked all ACEs using the same arithmetic and verified each ACE's size field fits within the buffer. The loop in replace_sids_and_copy_aces() iterates src_num_aces times (= le16_to_cpu(pdacl->num_aces)), the same count used by validate_dacl(). No counterexample exists: any pntace->size that would overflow or go OOB would have been caught by validate_dacl(). This is a false positive.

id_mode_to_cifs_acl() — fs/smb/client/cifsacl.c FP confidence=high

All 8 findings are false positives. The code follows a clear validation discipline: (1) dacl_offset_valid() is called before dacl_ptr is constructed, verifying that dacloffset is within bounds and that there is room for at least sizeof(struct smb_acl) at that offset; (2) validate_dacl() is then called with dacl_ptr before any fields of dacl_ptr are accessed in the caller; (3) findings #3-#8 flag accesses *inside* validate_dacl() itself — those accesses ARE the validation logic, not vulnerable sinks; (4) findings #1 and #2 (accessing dacl_ptr->num_aces and dacl_ptr->size in the caller) occur only AFTER validate_dacl() returns 0, meaning the dacl has already been fully traversed and validated. validate_dacl() checks: (a) end_of_acl >= pdacl + sizeof(smb_acl), establishing the struct header is readable; (b) dacl_size >= sizeof(smb_acl) and end_of_acl >= pdacl + dacl_size, so the full DACL fits; (c) num_aces is bounded by (dacl_size - sizeof(smb_acl)) / min_ace_size; (d) every ACE is bounds-checked in the loop. After validate_dacl() returns 0, accessing dacl_ptr->num_aces and dacl_ptr->size is safe.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1803
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Pointer derefdacl_ptr->num_aces line 1820
Sink snippetle16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
Possibly guardedno
Dismissed: dacl_ptr->num_aces is accessed at line 1820 only after dacl_offset_valid() (line 1805) confirms the offset is valid and validate_dacl() (line 1812) returns 0, which verifies end_of_acl >= pdacl + sizeof(smb_acl). Could not construct a counterexample: dacl_offset_valid ensures dacloffset + sizeof(smb_acl) <= secdesclen, and validate_dacl checks the header fits before reading any field. No OOB possible.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1803
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Pointer derefdacl_ptr->size line 1822
Sink snippetnsecdesclen += le16_to_cpu(dacl_ptr->size);
Possibly guardedno
Dismissed: dacl_ptr->size is accessed at line 1822 only after validate_dacl() returns 0. validate_dacl() verifies dacl_size >= sizeof(smb_acl) and end_of_acl >= pdacl + dacl_size, so the size field is safe to read. No counterexample exists.

Finding #3 — Category F — cross-function via validate_dacl() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 1803
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1812 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
Loopfor_loop line 875
Sink snippetfor (i = 0; i < num_aces; ++i) {
Possibly guardedyes (heuristic)
Dismissed: The sink is the for loop INSIDE validate_dacl() itself. validate_dacl() is the validation function — the loop bound (num_aces) is validated at line 866 against (dacl_size - sizeof(smb_acl)) / min_ace_size before the loop executes. Accesses inside the validator are the validation logic, not vulnerable sinks.

Finding #4 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1803
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1812 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
Pointer derefdacl_ptr-> line 885
Sink snippetpace->sid.num_subauth == 0 ||
Possibly guardedyes (heuristic)
Dismissed: pace->sid.num_subauth at line 885 is accessed inside validate_dacl() after the bounds check at line 884 (end_of_dacl - acl_base >= ace_hdr_size), which covers offsetof(smb_ace, sid) + offsetof(smb_sid, sub_auth), ensuring num_subauth is readable. This is part of the validation logic.

Finding #5 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1803
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1812 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
Pointer derefdacl_ptr-> line 886
Sink snippetpace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) {
Possibly guardedyes (heuristic)
Dismissed: Same as finding #4 — pace->sid.num_subauth at line 886 is covered by the ace_hdr_size check at line 884. Part of validation logic.

Finding #6 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1803
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1812 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
Pointer derefdacl_ptr-> line 891
Sink snippetace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth;
Possibly guardedyes (heuristic)
Dismissed: pace->sid.num_subauth at line 891 is accessed after the check at line 884-886 validates it is non-zero and <= SID_MAX_SUB_AUTHORITIES. The subsequent multiplication is safe. Part of validation logic.

Finding #7 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1803
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1812 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
Pointer derefdacl_ptr-> line 893
Sink snippetle16_to_cpu(pace->size) < ace_size) {
Possibly guardedyes (heuristic)
Dismissed: pace->size at line 893 is accessed after end_of_dacl - acl_base >= ace_size check at line 892, which ensures at least ace_size bytes are available, covering the ace header including the size field. Part of validation logic.

Finding #8 — Category E — cross-function via validate_dacl() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1803
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1812 — passes dacl_ptr to validate_dacl()
Call snippetrc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
Pointer derefdacl_ptr-> line 898
Sink snippetace_size = le16_to_cpu(pace->size);
Possibly guardedyes (heuristic)
Dismissed: pace->size at line 898 is accessed after the compound check at lines 892-896 confirms bounds. Part of validation logic inside validate_dacl().

parse_dacl() — fs/smb/client/cifsacl.c MIXED confidence=medium

parse_dacl() calls validate_dacl() before operating on the DACL, but validate_dacl() source is not available. The main loop (finding #1) lacks visible per-iteration bounds checks against end_of_acl, making it potentially vulnerable if validate_dacl() doesn't perform a full ACE traversal. Finding #2 concerns dump_ace() which only runs under CONFIG_CIFS_DEBUG2 and involves an OOB read via num_subauth. Finding #3 is a clear false positive due to min() bounding the iteration.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 942
Taint snippetnum_aces = le16_to_cpu(pdacl->num_aces);
Tainted varnum_aces
Loopfor_loop line 950
Sink snippetfor (i = 0; i < num_aces; ++i) {
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: KASAN: slab-out-of-bounds in parse_dacl when server supplies inflated num_aces or malformed per-ACE size fields, causing the loop to walk past end_of_acl
Fix: Add a per-iteration bounds check inside the loop: before dereferencing ppace[i], verify that (acl_base + acl_size + sizeof(struct smb_ace)) <= end_of_acl, and that le16_to_cpu(ppace[i]->size) >= sizeof(struct smb_ace) and that acl_base + acl_size + le16_to_cpu(ppace[i]->size) <= end_of_acl; break out of the loop if any check fails.
CVE pattern: SMB ACL parsing OOB read via unchecked server-supplied iteration count and per-element size field

Finding #2 — Category F — cross-function via dump_ace() (read-only callee) — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 942
Taint snippetnum_aces = le16_to_cpu(pdacl->num_aces);
Tainted varppace
Call siteline 954 — passes ppace to dump_ace()
Call snippetdump_ace(ppace[i],
Loopfor_loop line 824
Sink snippetfor (i = 0; i < num_subauth; ++i) {
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: Under CONFIG_CIFS_DEBUG2: KASAN: slab-out-of-bounds in dump_ace when pace->sid.num_subauth exceeds SID_MAX_SUB_AUTHORITIES (15), causing out-of-bounds read of sub_auth[] array
Fix: In dump_ace(), clamp num_subauth: num_subauth = min_t(u8, pace->sid.num_subauth, SID_MAX_SUB_AUTHORITIES) before the loop, or add an early return if num_subauth > SID_MAX_SUB_AUTHORITIES.
CVE pattern: SID num_subauth OOB read in debug path

Finding #3 — Category F — cross-function via compare_sids() (read-only callee) — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 942
Taint snippetnum_aces = le16_to_cpu(pdacl->num_aces);
Tainted varppace
Call siteline 959 — passes ppace to compare_sids()
Call snippet(compare_sids(&(ppace[i]->sid),
Loopfor_loop line 194
Sink snippetfor (i = 0; i < num_subauth; ++i) {
Possibly guardedyes (heuristic)
Dismissed: compare_sids() computes num_subauth = min(num_sat, num_saw) at line 192, bounding the loop to the minimum of both SIDs' subauth counts. No counterexample exists: any value of num_subauth from either SID is bounded by min(), so the loop cannot exceed either SID's sub_auth[] array size (though num_subauth itself is not clamped to SID_MAX_SUB_AUTHORITIES, the min ensures we never exceed what either pointer actually stores). This is a false positive.

parse_sec_desc() — fs/smb/client/cifsacl.c FP confidence=high

parse_sec_desc() has a solid validation chain. The dacloffset is validated by dacl_offset_valid() before dacl_ptr is computed. Inside parse_dacl(), validate_dacl() is called (line 927) before the loop at line 950 that uses num_aces. The loop bound (num_aces) comes from pdacl->num_aces, not directly from dacloffset. validate_dacl() is a dedicated validator that performs per-ACE bounds checks during traversal, establishing that num_aces and the ACE sizes are consistent with the buffer bounds defined by end_of_acl. The taint chain through dacloffset -> dacl_ptr -> num_aces is fully protected by two layers of validation.

Finding #1 — Category F — cross-function via parse_dacl() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 1348
Taint snippetdacloffset = le32_to_cpu(pntsd->dacloffset);
Tainted vardacl_ptr
Call siteline 1385 — passes dacl_ptr to parse_dacl()
Call snippetparse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Loopfor_loop line 950
Sink snippetfor (i = 0; i < num_aces; ++i) {
Possibly guardedyes (heuristic)
Dismissed: Two guards protect this path. First, dacl_offset_valid() at line 1379 validates that dacloffset falls within [sizeof(smb_ntsd), acl_len - sizeof(smb_acl)], making the dacl_ptr dereference safe. Second, parse_dacl() calls validate_dacl(pdacl, end_of_acl) at line 927 before the flagged loop at line 950. validate_dacl() is a dedicated DACL validator that walks the ACE array with per-element bounds checks against end_of_acl, establishing that num_aces and all ACE sizes are consistent with the available buffer. No counterexample can be constructed: any dacloffset that passes dacl_offset_valid() yields a dacl_ptr pointing to a valid smb_acl header within the buffer, and any num_aces that passes validate_dacl() is proven safe for the subsequent loop. The finding is a false positive.

replace_sids_and_copy_aces() — fs/smb/client/cifsacl.c FP confidence=medium

The function replace_sids_and_copy_aces() uses server-supplied num_aces to control loop iteration, but its sole call site in build_sec_desc() calls validate_dacl(dacl_ptr, end_of_acl) before reaching the call. validate_dacl() is expected to perform a full traversal of the DACL with per-element bounds checks using the same base pointer, num_aces count, and per-element size arithmetic, establishing a postcondition that makes the loop in replace_sids_and_copy_aces() safe. The 'prior full-traversal' protection pattern applies here.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 1206
Taint snippetsrc_num_aces = le16_to_cpu(pdacl->num_aces);
Tainted varsrc_num_aces
Loopfor_loop line 1212
Sink snippetfor (i = 0; i < src_num_aces; ++i) {
Possibly guardedno
Dismissed: validate_dacl(dacl_ptr, end_of_acl) is called at line 1425 in build_sec_desc() before replace_sids_and_copy_aces() is called at line 1529. If validate_dacl performs a full traversal of ACEs using structurally equivalent arithmetic (same pdacl base, same num_aces, same per-element pntace->size), it establishes a precondition that prevents OOB in the subsequent loop. No counterexample can be constructed because any num_aces value that would cause OOB would have been rejected by validate_dacl. Confidence is medium rather than high because validate_dacl source is not shown in the prompt, making this inference based on naming conventions and call patterns.

set_chmod_dacl() — fs/smb/client/cifsacl.c FP confidence=medium

The caller build_sec_desc() calls validate_dacl(dacl_ptr, end_of_acl) before set_chmod_dacl(). This validator appears to perform a full traversal of the DACL with per-ACE bounds checking using the same base pointer, num_aces count, and per-element size field advancement. The loop in set_chmod_dacl() uses structurally identical arithmetic over the same buffer, so the prior traversal in validate_dacl establishes safety for this loop. Without the validate_dacl source we cannot be 100% certain, but the naming convention, return-value pattern, and end_of_acl parameter strongly indicate comprehensive validation.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 1263
Taint snippetsrc_num_aces = le16_to_cpu(pdacl->num_aces);
Tainted varsrc_num_aces
Loopfor_loop line 1266
Sink snippetfor (i = 0; i < src_num_aces; ++i) {
Possibly guardedno
Dismissed: The caller invokes validate_dacl(dacl_ptr, end_of_acl) before calling set_chmod_dacl(). validate_dacl is expected to fully traverse the DACL with per-ACE bounds checks against end_of_acl, establishing that all num_aces ACEs are within bounds. The loop in set_chmod_dacl() uses the same arithmetic (acl_base, size += le16_to_cpu(pntace->size), i < src_num_aces), so it is protected by the prior traversal. Could not construct a counterexample that passes validate_dacl yet causes OOB in this loop, assuming validate_dacl is a proper full-traversal validator. Confidence is medium rather than high due to not having validate_dacl source included.

validate_dacl() — fs/smb/client/cifsacl.c FP confidence=high

validate_dacl() has strong validation discipline: a pre-loop density check bounds num_aces relative to the buffer size, and every iteration of the loop checks remaining buffer space before dereferencing pace. The per-iteration guards (end_of_dacl - acl_base < ace_size/ace_hdr_size) provide form (b) protection — the loop terminates with -EINVAL before any OOB access, regardless of how large num_aces is.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 859
Taint snippetnum_aces = le16_to_cpu(pdacl->num_aces);
Tainted varnum_aces
Loopfor_loop line 875
Sink snippetfor (i = 0; i < num_aces; ++i) {
Possibly guardedyes (heuristic)
Dismissed: Two layers of protection: (1) pre-loop density check at line 866 ensures num_aces * min_ace_size <= available buffer space, so the loop cannot iterate more times than there are minimum-size ACEs in the buffer; (2) per-iteration bounds checks before every pointer dereference (lines 876, 884, 892, 899) return -EINVAL if the remaining buffer is too small. No counterexample can be constructed: any num_aces value that passes the density check will be exhausted by per-iteration guards before any OOB access occurs.

CIFSFindFirst() — fs/smb/client/cifssmb.c BUG confidence=medium

validate_t2() is called before accessing parms, but its validation may not guarantee that ParameterOffset + sizeof(T2_FFIRST_RSP_PARMS) fits within the buffer. A malicious server could provide a ParameterOffset that causes parms to point near the end of the buffer, allowing field accesses to read beyond it. The lnoff guard on line 4516 only checks lnoff against CIFSMaxBufSize but not against actual packet boundaries, and doesn't protect the earlier parms field accesses.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4508
Taint snippetparms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol +
Tainted varparms
Pointer derefparms->EndofSearch line 4510
Sink snippetpsrch_inf->endOfSearch = !!parms->EndofSearch;
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSFindFirst when accessing parms->EndofSearch with a crafted ParameterOffset near end of buffer
Fix: After computing parms, verify that (char*)parms + sizeof(T2_FFIRST_RSP_PARMS) <= (char*)pSMBr + bytes_returned before accessing any parms fields.
CVE pattern: CVE-2022-NNNN style DataOffset/ParameterOffset OOB in SMBv1 transaction2 response parsing

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4508
Taint snippetparms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol +
Tainted varparms
Pointer derefparms->SearchCount line 4512
Sink snippetpsrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSFindFirst when accessing parms->SearchCount with crafted ParameterOffset
Fix: Validate (char*)parms + sizeof(T2_FFIRST_RSP_PARMS) <= (char*)pSMBr + bytes_returned before accessing any parms fields.
CVE pattern: CVE-2022-NNNN style ParameterOffset OOB in SMBv1 TRANS2 response

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4508
Taint snippetparms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol +
Tainted varparms
Pointer derefparms->LastNameOffset line 4515
Sink snippetlnoff = le16_to_cpu(parms->LastNameOffset);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSFindFirst when accessing parms->LastNameOffset with crafted ParameterOffset
Fix: Validate (char*)parms + sizeof(T2_FFIRST_RSP_PARMS) <= (char*)pSMBr + bytes_returned before accessing parms fields.
CVE pattern: CVE-2022-NNNN style ParameterOffset OOB in SMBv1 TRANS2 response

Finding #4 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4508
Taint snippetparms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol +
Tainted varparms
Pointer derefparms->SearchHandle line 4522
Sink snippet*pnetfid = parms->SearchHandle;
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSFindFirst when accessing parms->SearchHandle with crafted ParameterOffset
Fix: Validate (char*)parms + sizeof(T2_FFIRST_RSP_PARMS) <= (char*)pSMBr + bytes_returned before accessing any parms fields.
CVE pattern: CVE-2022-NNNN style ParameterOffset OOB in SMBv1 TRANS2 response

CIFSFindNext() — fs/smb/client/cifssmb.c BUG confidence=high

validate_t2() is called at line 4610 before the parms pointer is constructed. The critical question is what validate_t2() checks. It validates the T2 response header structure but does NOT verify that ParameterOffset + sizeof(T2_FNEXT_RSP_PARMS) lies within the received packet bounds. The ParameterOffset comes directly from the server (le16_to_cpu(pSMBr->t2.ParameterOffset) at line 4618) and can point anywhere in the received buffer or beyond. There is no check that the derived 'parms' pointer (and the size of T2_FNEXT_RSP_PARMS) fits within the actual received packet before accessing parms->EndofSearch, parms->SearchCount, and parms->LastNameOffset. The lnoff check at line 4635 only validates lnoff against CIFSMaxBufSize (not the actual bytes_returned), and occurs after parms fields have already been dereferenced. All three findings share the same root cause: unvalidated ParameterOffset from the server.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4617
Taint snippetresponse_data = (char *)&pSMBr->hdr.Protocol +
Tainted varparms
Pointer derefparms->EndofSearch line 4631
Sink snippetpsrch_inf->endOfSearch = !!parms->EndofSearch;
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSFindNext when server sends a ParameterOffset placing parms beyond the received packet buffer, causing out-of-bounds read of parms->EndofSearch
Fix: After validate_t2() succeeds, verify that le16_to_cpu(pSMBr->t2.ParameterOffset) + sizeof(T2_FNEXT_RSP_PARMS) <= bytes_returned (or the actual received buffer size) before casting response_data to T2_FNEXT_RSP_PARMS*. Return -EIO if the check fails.
CVE pattern: SMB response DataOffset/ParameterOffset OOB read (similar to CVE-2011-1090 style T2 parameter offset validation issues)

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4617
Taint snippetresponse_data = (char *)&pSMBr->hdr.Protocol +
Tainted varparms
Pointer derefparms->SearchCount line 4632
Sink snippetpsrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSFindNext when server sends a ParameterOffset placing parms beyond the received packet buffer, causing out-of-bounds read of parms->SearchCount
Fix: Same as finding #1: validate ParameterOffset + sizeof(T2_FNEXT_RSP_PARMS) <= bytes_returned before using the parms pointer.
CVE pattern: SMB response DataOffset/ParameterOffset OOB read

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4617
Taint snippetresponse_data = (char *)&pSMBr->hdr.Protocol +
Tainted varparms
Pointer derefparms->LastNameOffset line 4634
Sink snippetlnoff = le16_to_cpu(parms->LastNameOffset);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSFindNext; even if parms pointer access doesn't OOB, the lnoff check at line 4635 compares against CIFSMaxBufSize rather than actual bytes_returned, so a value just below CIFSMaxBufSize but beyond actual received data causes OOB read when computing psrch_inf->last_entry
Fix: Same as finding #1 for the parms pointer access. Additionally, the lnoff check should compare against the actual DataCount/received data length rather than CIFSMaxBufSize.
CVE pattern: SMB response DataOffset/ParameterOffset OOB read

CIFSGetExtAttr() — fs/smb/client/cifssmb.c BUG confidence=high

pSMBr is a server response buffer. data_offset is read directly from the server-supplied DataOffset field. The only check performed before using it is that DataCount == 16, which validates the size of the data but does NOT validate that data_offset places the 16-byte struct within the bounds of the received packet. A malicious server could supply a DataOffset that, when added to &pSMBr->hdr.Protocol, points outside the received buffer. validate_t2() is called, but it does not validate DataOffset against packet_end — it only validates TotalDataCount and BCC. There is no check that data_offset + sizeof(*pfinfo) <= bytes_returned (or packet end). This is a genuine OOB read vulnerability.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 3695
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varpfinfo
Pointer derefpfinfo->mode line 3707
Sink snippet*pExtAttrBits = le64_to_cpu(pfinfo->mode);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSGetExtAttr reading pfinfo->mode; or kernel panic / info disclosure if a malicious server sets DataOffset to push pfinfo beyond the received buffer
Fix: After validating count==16, also verify that data_offset is sane: check that (char *)&pSMBr->hdr.Protocol + data_offset + sizeof(*pfinfo) <= (char *)pSMBr + bytes_returned (i.e., does not exceed the end of the received packet). Return -EIO if the check fails.
CVE pattern: DataOffset OOB read in SMB/CIFS response parsing, similar to CVE-2011-1013 style CIFS DataOffset validation bugs

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 3695
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varpfinfo
Pointer derefpfinfo->mask line 3708
Sink snippet*pMask = le64_to_cpu(pfinfo->mask);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSGetExtAttr reading pfinfo->mask; same root cause as finding #1, just the second field of the same out-of-bounds struct pointer
Fix: Same fix as finding #1 — validate data_offset + sizeof(struct file_chattr_info) <= packet_end before computing pfinfo. Both ->mode and ->mask accesses are covered by the single bounds check.
CVE pattern: DataOffset OOB read in SMB/CIFS response parsing, same as finding #1

CIFSGetSrvInodeNumber() — fs/smb/client/cifssmb.c BUG confidence=high

The function validates that DataCount >= 8 and that BCC >= 2, and calls validate_t2() which checks basic T2 response structure, but does NOT validate that data_offset + sizeof(*pfinfo) falls within the actual received packet bounds. A malicious server could supply a DataOffset value that, when added to &pSMBr->hdr.Protocol, points outside the packet buffer, causing an out-of-bounds read.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4762
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varpfinfo
Pointer derefpfinfo->UniqueId line 4774
Sink snippet*inode_number = le64_to_cpu(pfinfo->UniqueId);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSGetSrvInodeNumber or kernel crash when dereferencing pfinfo->UniqueId with a crafted DataOffset value
Fix: After computing pfinfo, verify that the derived pointer plus sizeof(*pfinfo) does not exceed the end of the received response buffer. Specifically: char *buf_end = (char *)pSMBr + bytes_returned; if ((char *)pfinfo + sizeof(*pfinfo) > buf_end || (char *)pfinfo < (char *)&pSMBr->hdr.Protocol) { rc = -EIO; goto GetInodeNumOut; }
CVE pattern: CVE-2022-NNNN style DataOffset OOB — server-controlled T2 DataOffset used without upper-bound validation against packet length, similar to historical CIFS SMB1 DataOffset OOB vulnerabilities

CIFSPOSIXCreate() — fs/smb/client/cifssmb.c VALIDATE confidence=medium

The function validates the T2 response via validate_t2() and checks BCC >= sizeof(OPEN_PSX_RSP) before using psx_rsp. However, the DataOffset used to compute psx_rsp is server-supplied and the BCC check alone does not bound the DataOffset value. If validate_t2() verifies DataOffset+DataCount fits within the response buffer (which is typical for CIFS T2 validators), then all findings are false positives. Without the validate_t2() source, the sufficiency cannot be confirmed with certainty. The memcpy source (finding #5) has an additional guard checking BCC >= sizeof(OPEN_PSX_RSP)+sizeof(FILE_UNIX_BASIC_INFO), but this still doesn't directly constrain DataOffset.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1132
Taint snippetpsx_rsp = (OPEN_PSX_RSP *)
Tainted varpsx_rsp
Pointer derefpsx_rsp->OplockFlags line 1135
Sink snippet*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSPOSIXCreate when server supplies a crafted DataOffset placing psx_rsp outside the response buffer
Fix: After computing psx_rsp, verify that (char*)psx_rsp + sizeof(OPEN_PSX_RSP) <= (char*)pSMBr + total_response_size. The DataOffset must be checked to ensure psx_rsp falls within the actual response buffer, not just that BCC is large enough.
CVE pattern: DataOffset out-of-bounds in SMB T2 response parsing

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1132
Taint snippetpsx_rsp = (OPEN_PSX_RSP *)
Tainted varpsx_rsp
Pointer derefpsx_rsp->Fid line 1137
Sink snippet*netfid = psx_rsp->Fid; /* cifs fid stays in le */
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading psx_rsp->Fid in CIFSPOSIXCreate
Fix: Same as finding #1: validate DataOffset before computing psx_rsp pointer.
CVE pattern: DataOffset out-of-bounds in SMB T2 response parsing

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1132
Taint snippetpsx_rsp = (OPEN_PSX_RSP *)
Tainted varpsx_rsp
Pointer derefpsx_rsp->CreateAction line 1140
Sink snippetif (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading psx_rsp->CreateAction in CIFSPOSIXCreate
Fix: Same as finding #1: validate DataOffset before computing psx_rsp pointer.
CVE pattern: DataOffset out-of-bounds in SMB T2 response parsing

Finding #4 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1132
Taint snippetpsx_rsp = (OPEN_PSX_RSP *)
Tainted varpsx_rsp
Pointer derefpsx_rsp->ReturnedLevel line 1143
Sink snippetif (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading psx_rsp->ReturnedLevel in CIFSPOSIXCreate
Fix: Same as finding #1: validate DataOffset before computing psx_rsp pointer.
CVE pattern: DataOffset out-of-bounds in SMB T2 response parsing

Finding #5 — Category A — BUG oob_read

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 1132
Taint snippetpsx_rsp = (OPEN_PSX_RSP *)
Tainted varpsx_rsp
Sinkmemcpy() line 1153 (arg 1, role=pointer)
Sink snippetmemcpy(pRetData,
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in memcpy source within CIFSPOSIXCreate when DataOffset is crafted to place psx_rsp near or beyond packet end
Fix: Validate DataOffset so that (char*)psx_rsp + sizeof(OPEN_PSX_RSP) + sizeof(FILE_UNIX_BASIC_INFO) <= packet_end before performing memcpy. The BCC guard at line 1147 helps but does not bound DataOffset independently.
CVE pattern: DataOffset out-of-bounds in SMB T2 response parsing

CIFSSMBPosixLock() — fs/smb/client/cifssmb.c BUG confidence=high

The function validates data_count >= sizeof(struct cifs_posix_lock) but does not verify that data_offset + sizeof(struct cifs_posix_lock) <= packet_end before constructing parm_data from the server-supplied data_offset. A malicious server can supply a large DataOffset that passes the data_count check yet places parm_data beyond the actual receive buffer, enabling OOB reads. All 7 findings share this single root cause.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2370
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varparm_data
Pointer derefparm_data->lock_type line 2379
Sink snippetif (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBPosixLock when server returns a crafted DataOffset placing parm_data beyond the receive buffer
Fix: After computing parm_data, verify that (char*)parm_data + sizeof(struct cifs_posix_lock) <= (char*)pSMBr + total_packet_size. Specifically: validate that data_offset + sizeof(struct cifs_posix_lock) does not exceed the bounds of the received buffer (e.g., check against get_bcc + offsetof(hdr, Protocol) or use validate_t2's returned length).
CVE pattern: CVE-2022-NNNN style DataOffset OOB — unvalidated server-supplied offset used for pointer arithmetic in SMB response parsing

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2370
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varparm_data
Pointer derefparm_data->lock_type line 2382
Sink snippetif (parm_data->lock_type ==
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBPosixLock when server returns a crafted DataOffset
Fix: Validate data_offset + sizeof(struct cifs_posix_lock) <= received buffer length before deriving parm_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2370
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varparm_data
Pointer derefparm_data->lock_type line 2385
Sink snippetelse if (parm_data->lock_type ==
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBPosixLock when server returns a crafted DataOffset
Fix: Validate data_offset + sizeof(struct cifs_posix_lock) <= received buffer length before deriving parm_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB

Finding #4 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2370
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varparm_data
Pointer derefparm_data->start line 2389
Sink snippetpLockData->fl_start = le64_to_cpu(parm_data->start);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBPosixLock accessing parm_data->start
Fix: Validate data_offset + sizeof(struct cifs_posix_lock) <= received buffer length before deriving parm_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB

Finding #5 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2370
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varparm_data
Pointer derefparm_data->length line 2391
Sink snippet(le64_to_cpu(parm_data->length) ?
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBPosixLock accessing parm_data->length
Fix: Validate data_offset + sizeof(struct cifs_posix_lock) <= received buffer length before deriving parm_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB

Finding #6 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2370
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varparm_data
Pointer derefparm_data->length line 2392
Sink snippetle64_to_cpu(parm_data->length) - 1 : 0);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBPosixLock accessing parm_data->length
Fix: Validate data_offset + sizeof(struct cifs_posix_lock) <= received buffer length before deriving parm_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB

Finding #7 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2370
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varparm_data
Pointer derefparm_data->pid line 2393
Sink snippetpLockData->c.flc_pid = -le32_to_cpu(parm_data->pid);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBPosixLock accessing parm_data->pid
Fix: Validate data_offset + sizeof(struct cifs_posix_lock) <= received buffer length before deriving parm_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB

CIFSSMBQAllEAs() — fs/smb/client/cifssmb.c MIXED confidence=medium

The function has layered validation but with a critical gap: data_offset from the server is not validated against the packet bounds before ea_response_data is constructed and dereferenced. The end-of-SMB check at line 6226 only runs AFTER already dereferencing ea_response_data->list_len. The per-iteration loop bounds checks (list_len < 0 after subtracting fixed header size 4) are sufficient for protecting name_len/value_len reads since the 4-byte subtraction accounts for the fea fixed-header fields. The memcpy/memcmp operations are generally protected: value_len is checked against buf_size before the copy; name_len is bounded by list_len (already bounded to end_of_smb). The memcpy(EAData, temp_ptr, name_len) at line 6280 has a weaker destination check (accumulated rc vs buf_size) that may be insufficient.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6210
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varea_response_data
Pointer derefea_response_data->list_len line 6214
Sink snippetlist_len = le32_to_cpu(ea_response_data->list_len);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQAllEAs when server supplies a DataOffset that places ea_response_data->list_len beyond the packet buffer
Fix: Before computing ea_response_data, validate that data_offset + sizeof(struct fealist) <= (size of packet buffer derived from bcc and hdr). Specifically: if (data_offset < sizeof(pSMBr->hdr) || data_offset + sizeof(struct fealist) > (char*)end_of_smb - (char*)&pSMBr->hdr.Protocol) { rc = -EIO; goto QAllEAsOut; }
CVE pattern: CVE-2022-NNNN style DataOffset OOB — server-controlled offset used without pre-dereference bounds check

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6210
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varea_response_data
Pointer derefea_response_data->list line 6236
Sink snippettemp_fea = &ea_response_data->list;
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQAllEAs — ea_response_data->list field accessed before offset is validated against packet end
Fix: Same fix as finding #1: validate data_offset + sizeof(struct fealist) fits within packet before computing ea_response_data. The list field is at offset 4 inside fealist, so the same bounds check covers it.
CVE pattern: CVE-2022-NNNN style DataOffset OOB

Finding #3 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 6214
Taint snippetlist_len = le32_to_cpu(ea_response_data->list_len);
Tainted varlist_len
Loopwhile_loop line 6238
Sink snippetwhile (list_len > 0) {
Possibly guardedyes (heuristic)
Dismissed: list_len is bounded against end_of_smb at line 6226 before the loop. Inside the loop, list_len is decremented by 4 and checked < 0, then decremented by name_len+1+value_len and checked < 0 again. These per-iteration guards ensure the loop terminates before going past end_of_smb. Counterexample attempt: list_len=8 → exits at line 6216. list_len=9, loop: subtract 4 → 5 >= 0 ok, read name_len=5, value_len=0, subtract 6 → -1 < 0 → error exit. No OOB path found.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6210
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted vartemp_fea
Pointer dereftemp_fea->name_len line 6251
Sink snippetname_len = temp_fea->name_len;
Possibly guardedno
Dismissed: temp_fea->name_len is read after subtracting 4 from list_len and verifying list_len >= 0 (i.e., at least 4 bytes remain). struct fea has a 1-byte reserved, 1-byte name_len, 2-byte value_len = 4 bytes fixed header, so the 4-byte reservation is exact. temp_fea is derived from temp_ptr which stays within the ea_response_data region (bounded by end_of_smb check). No OOB counterexample constructible.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6210
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted vartemp_fea
Pointer dereftemp_fea->value_len line 6252
Sink snippetvalue_len = le16_to_cpu(temp_fea->value_len);
Possibly guardedno
Dismissed: Same reasoning as finding #4. value_len is at offset 2 within the 4-byte fea header. The 4-byte subtraction and list_len >= 0 check covers both name_len (offset 1) and value_len (offset 2). False positive.

Finding #6 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 6210
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varname_len
Sinkmemcmp() line 6262 (arg 2, role=size)
Sink snippetmemcmp(ea_name, temp_ptr, name_len) == 0) {
Possibly guardedyes (heuristic)
Dismissed: name_len is an unsigned int derived from temp_fea->name_len (u8, so max 255). The source buffer (temp_ptr) is bounded: list_len check ensures name_len + 1 + value_len <= remaining list_len <= end_of_smb - temp_ptr. For the destination (ea_name), memcmp reads ea_name up to name_len bytes; ea_name is caller-supplied and the comparison is checking equality with ea_name_len == name_len first, so name_len is bounded by ea_name_len which is computed from strlen(ea_name) in the caller. No OOB.

Finding #7 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 6210
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted vartemp_ptr
Sinkmemcmp() line 6262 (arg 1, role=pointer)
Sink snippetmemcmp(ea_name, temp_ptr, name_len) == 0) {
Possibly guardedyes (heuristic)
Dismissed: temp_ptr at the memcmp call points to the name field of the current fea entry. The list_len bounds checks ensure temp_ptr + name_len stays within the validated buffer region (bounded by end_of_smb). False positive.

Finding #8 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 6252
Taint snippetvalue_len = le16_to_cpu(temp_fea->value_len);
Tainted varvalue_len
Sinkmemcpy() line 6271 (arg 2, role=size)
Sink snippetmemcpy(EAData, temp_ptr, value_len);
Possibly guardedyes (heuristic)
Dismissed: Source: value_len bounded by list_len check (name_len+1+value_len <= remaining list_len <= end_of_smb - base). Destination: line 6267 checks (size_t)value_len > buf_size before the memcpy, ensuring EAData has enough space. Both source and destination are checked. False positive.

Finding #9 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 6210
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted vartemp_ptr
Sinkmemcpy() line 6271 (arg 1, role=pointer)
Sink snippetmemcpy(EAData, temp_ptr, value_len);
Possibly guardedyes (heuristic)
Dismissed: temp_ptr at the memcpy call (line 6271) has been advanced by name_len+1. The remaining bytes (value_len) are within the bounds validated by the list_len accounting. False positive.

Finding #10 — Category B — BUG oob_write

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 6210
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varname_len
Sinkmemcpy() line 6280 (arg 2, role=size)
Sink snippetmemcpy(EAData, temp_ptr, name_len);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQAllEAs — memcpy writes name_len bytes into EAData without checking remaining EAData buffer capacity
Fix: Before the memcpy at line 6280, verify that the current EAData pointer plus the number of bytes to be written (5 + name_len + 1) does not exceed EAData_start + buf_size. The current check 'rc < (int)buf_size' uses the accumulated total, not the remaining space at the current EAData pointer, and may allow an individual name_len copy to overflow if prior entries consumed buffer space.
CVE pattern: Insufficient destination buffer check before memcpy with server-controlled size

Finding #11 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 6210
Taint snippetdata_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted vartemp_ptr
Sinkmemcpy() line 6280 (arg 1, role=pointer)
Sink snippetmemcpy(EAData, temp_ptr, name_len);
Possibly guardedyes (heuristic)
Dismissed: Same reasoning as finding #10 revision. temp_ptr is within the validated server buffer region. The destination EAData is protected by the rc < buf_size check which tracks total bytes written. False positive.

CIFSSMBQFSAttributeInfo() — fs/smb/client/cifssmb.c BUG confidence=high

The function calls validate_t2() and checks BCC >= 13, but neither check validates that DataOffset from the server response actually points within the response buffer before using it for pointer arithmetic. A server can supply an arbitrary DataOffset value (up to 65535 as a __u16) causing response_data to point far beyond the pSMBr buffer, leading to an OOB read into the memcpy source argument.

Finding #1 — Category A — BUG oob_read

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 5139
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Sinkmemcpy() line 5144 (arg 1, role=pointer)
Sink snippetmemcpy(&tcon->fsAttrInfo, response_data,
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQFSAttributeInfo (memcpy reading beyond the response buffer), or kernel panic / info disclosure from reading attacker-controlled memory into tcon->fsAttrInfo
Fix: After extracting data_offset, validate it: ensure data_offset is within the received buffer bounds, i.e., data_offset + sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) <= bytes_returned (or the total response buffer size). For example: if (data_offset < sizeof(pSMBr->hdr) || data_offset + sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) > (unsigned int)bytes_returned) { rc = -EIO; } else { /* proceed with memcpy */ }
CVE pattern: SMB response DataOffset out-of-bounds read (similar pattern to CVE-2011-1013 and related CIFS DataOffset OOB vulnerabilities)

CIFSSMBQFSDeviceInfo() — fs/smb/client/cifssmb.c BUG confidence=high

The function validates BCC size but not the DataOffset field from the server response. DataOffset is server-supplied via le16_to_cpu() and used directly in pointer arithmetic without any bounds check, allowing a malicious server to craft a DataOffset that points outside the response buffer. The BCC check (line 5208-5212) only verifies the byte count is large enough for the struct, but does NOT validate that DataOffset places response_data within a safe region of the buffer.

Finding #1 — Category A — BUG oob_read

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 5214
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Sinkmemcpy() line 5219 (arg 1, role=pointer)
Sink snippetmemcpy(&tcon->fsDevInfo, response_data,
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQFSDeviceInfo — memcpy reads sizeof(FILE_SYSTEM_DEVICE_INFO) bytes from an attacker-controlled offset relative to &pSMBr->hdr.Protocol, potentially reading memory far outside the response buffer
Fix: After validate_t2() succeeds, validate data_offset: check that (data_offset + sizeof(FILE_SYSTEM_DEVICE_INFO)) <= bytes_returned (or the actual SMB response buffer length), and that data_offset >= minimum safe offset (e.g., sizeof the SMB header fields), before computing response_data and calling memcpy. For example: if (data_offset < sizeof(pSMBr->hdr) || data_offset + sizeof(FILE_SYSTEM_DEVICE_INFO) > bytes_returned) { rc = -EIO; } else { ... memcpy ... }
CVE pattern: CVE-2022-NNNN style DataOffset OOB — server-controlled DataOffset used in pointer arithmetic without upper-bound validation before memcpy, similar to multiple historical CIFS/SMB DataOffset OOB vulnerabilities

CIFSSMBQFSInfo() — fs/smb/client/cifssmb.c BUG confidence=high

The function calls validate_t2() and checks BCC >= 24, but neither check validates the server-supplied DataOffset field. validate_t2() verifies the TRANSACTION2 response structure is minimally sane, but does not bound-check DataOffset against the packet end. The BCC check (>= 24) ensures the byte count field says there are at least 24 bytes of data, but the actual data_offset value (from pSMBr->t2.DataOffset) could point anywhere in or beyond the packet buffer. A malicious or malformed server could supply a DataOffset that places response_data outside the received packet, leading to an out-of-bounds read when fields like BytesPerSector, SectorsPerAllocationUnit, TotalAllocationUnits, and AvailableAllocationUnits are accessed.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5048
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->BytesPerSector line 5055
Sink snippetle32_to_cpu(response_data->BytesPerSector) *
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQFSInfo reading beyond response buffer when accessing response_data->BytesPerSector
Fix: After computing data_offset, validate that data_offset + sizeof(FILE_SYSTEM_SIZE_INFO) <= bytes_returned (or total packet size). Specifically: if (data_offset > bytes_returned || bytes_returned - data_offset < sizeof(FILE_SYSTEM_SIZE_INFO)) { rc = -EIO; } before using response_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB in SMB TRANSACTION2 response

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5048
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->SectorsPerAllocationUnit line 5056
Sink snippetle32_to_cpu(response_data->
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQFSInfo reading beyond response buffer when accessing response_data->SectorsPerAllocationUnit
Fix: After computing data_offset, validate that data_offset + sizeof(FILE_SYSTEM_SIZE_INFO) <= bytes_returned before dereferencing response_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB in SMB TRANSACTION2 response

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5048
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->TotalAllocationUnits line 5066
Sink snippetle64_to_cpu(response_data->TotalAllocationUnits);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQFSInfo reading beyond response buffer when accessing response_data->TotalAllocationUnits
Fix: After computing data_offset, validate that data_offset + sizeof(FILE_SYSTEM_SIZE_INFO) <= bytes_returned before dereferencing response_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB in SMB TRANSACTION2 response

Finding #4 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5048
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->AvailableAllocationUnits line 5068
Sink snippetle64_to_cpu(response_data->AvailableAllocationUnits);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQFSInfo reading beyond response buffer when accessing response_data->AvailableAllocationUnits
Fix: After computing data_offset, validate that data_offset + sizeof(FILE_SYSTEM_SIZE_INFO) <= bytes_returned before dereferencing response_data.
CVE pattern: CVE-2022-NNNN style DataOffset OOB in SMB TRANSACTION2 response

CIFSSMBQFSPosixInfo() — fs/smb/client/cifssmb.c VALIDATE confidence=medium

The function calls validate_t2() before using DataOffset, and checks BCC >= 13. Whether validate_t2() sufficiently validates DataOffset + sizeof(FILE_SYSTEM_POSIX_INFO) <= packet_end determines if these are real bugs. The BCC >= 13 check alone does not bound DataOffset arithmetic. Standard CIFS validate_t2() implementations do check DataOffset against smb_buf_length, which would make these false positives; without that source, confidence is medium.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5435
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->BlockSize line 5441
Sink snippetle32_to_cpu(response_data->BlockSize);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQFSPosixInfo if validate_t2 does not bound DataOffset+sizeof(FILE_SYSTEM_POSIX_INFO) within packet
Fix: After validate_t2() and BCC check, also verify that data_offset + sizeof(FILE_SYSTEM_POSIX_INFO) <= smb_buf_length(pSMBr) before casting response_data pointer
CVE pattern: CVE-2022 style DataOffset OOB in SMB TRANSACTION2 response parsing

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5435
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->TotalBlocks line 5450
Sink snippetle64_to_cpu(response_data->TotalBlocks);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading TotalBlocks field beyond packet boundary
Fix: Validate data_offset + sizeof(FILE_SYSTEM_POSIX_INFO) <= packet size before dereferencing response_data
CVE pattern: CVE-2022 style DataOffset OOB in SMB TRANSACTION2 response parsing

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5435
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->BlocksAvail line 5452
Sink snippetle64_to_cpu(response_data->BlocksAvail);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading BlocksAvail field beyond packet boundary
Fix: Validate data_offset + sizeof(FILE_SYSTEM_POSIX_INFO) <= packet size before dereferencing response_data
CVE pattern: CVE-2022 style DataOffset OOB in SMB TRANSACTION2 response parsing

Finding #4 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5435
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->UserBlocksAvail line 5453
Sink snippetif (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading UserBlocksAvail field beyond packet boundary
Fix: Validate data_offset + sizeof(FILE_SYSTEM_POSIX_INFO) <= packet size before dereferencing response_data
CVE pattern: CVE-2022 style DataOffset OOB in SMB TRANSACTION2 response parsing

Finding #5 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5435
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->UserBlocksAvail line 5457
Sink snippetle64_to_cpu(response_data->UserBlocksAvail);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading UserBlocksAvail field beyond packet boundary
Fix: Validate data_offset + sizeof(FILE_SYSTEM_POSIX_INFO) <= packet size before dereferencing response_data
CVE pattern: CVE-2022 style DataOffset OOB in SMB TRANSACTION2 response parsing

Finding #6 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5435
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->TotalFileNodes line 5459
Sink snippetif (response_data->TotalFileNodes != cpu_to_le64(-1))
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading TotalFileNodes field beyond packet boundary
Fix: Validate data_offset + sizeof(FILE_SYSTEM_POSIX_INFO) <= packet size before dereferencing response_data
CVE pattern: CVE-2022 style DataOffset OOB in SMB TRANSACTION2 response parsing

Finding #7 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5435
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->TotalFileNodes line 5461
Sink snippetle64_to_cpu(response_data->TotalFileNodes);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading TotalFileNodes field beyond packet boundary
Fix: Validate data_offset + sizeof(FILE_SYSTEM_POSIX_INFO) <= packet size before dereferencing response_data
CVE pattern: CVE-2022 style DataOffset OOB in SMB TRANSACTION2 response parsing

Finding #8 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5435
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->FreeFileNodes line 5462
Sink snippetif (response_data->FreeFileNodes != cpu_to_le64(-1))
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading FreeFileNodes field beyond packet boundary
Fix: Validate data_offset + sizeof(FILE_SYSTEM_POSIX_INFO) <= packet size before dereferencing response_data
CVE pattern: CVE-2022 style DataOffset OOB in SMB TRANSACTION2 response parsing

Finding #9 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 5435
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->FreeFileNodes line 5464
Sink snippetle64_to_cpu(response_data->FreeFileNodes);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading FreeFileNodes field beyond packet boundary
Fix: Validate data_offset + sizeof(FILE_SYSTEM_POSIX_INFO) <= packet size before dereferencing response_data
CVE pattern: CVE-2022 style DataOffset OOB in SMB TRANSACTION2 response parsing

CIFSSMBQFSUnixInfo() — fs/smb/client/cifssmb.c BUG confidence=high

The function sends a request, receives a response, and calls validate_t2() plus a BCC size check before using DataOffset. However, validate_t2() only checks that the T2 response is structurally valid (parameter/data offsets fit within the SMB buffer), and the BCC check (< 13) only verifies minimum data size. Neither check bounds pSMBr->t2.DataOffset against the actual response buffer before using it in pointer arithmetic to derive response_data. A server-supplied DataOffset that points beyond the response buffer would cause an OOB read via memcpy().

Finding #1 — Category A — BUG oob_read

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 5286
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Sinkmemcpy() line 5291 (arg 1, role=pointer)
Sink snippetmemcpy(&tcon->fsUnixInfo, response_data,
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in CIFSSMBQFSUnixInfo; kernel crash or memory corruption when memcpy reads beyond the response buffer using a crafted DataOffset value
Fix: After reading data_offset, validate that data_offset is within the received buffer: check that (data_offset + sizeof(FILE_SYSTEM_UNIX_INFO)) <= (bytes_returned - offsetof(TRANSACTION2_QFSI_RSP, hdr.Protocol)) before computing response_data and calling memcpy(). Also ensure data_offset >= offsetof(TRANSACTION2_QFSI_RSP, t2) to avoid pointing before the T2 data area.
CVE pattern: SMB T2 response DataOffset out-of-bounds read — similar pattern to CVE-2011-1090 and related CIFS T2 DataOffset OOB vulnerabilities

CIFSSMBRead() — fs/smb/client/cifssmb.c MIXED confidence=high

pSMBr is the server response buffer. data_length is properly bounded against CIFSMaxBufSize and count (finding #1 is a false positive). However, DataOffset (pSMBr->DataOffset) used in pointer arithmetic to compute pReadData is not bounds-checked against the response buffer size, allowing a malicious server to set DataOffset such that pReadData points before or beyond the response buffer, causing an OOB read (finding #2 is a real bug).

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1717
Taint snippetint data_length = le16_to_cpu(pSMBr->DataLengthHigh);
Tainted vardata_length
Sinkmemcpy() line 1738 (arg 2, role=size)
Sink snippetmemcpy(*buf, pReadData, data_length);
Possibly guardedyes (heuristic)
Dismissed: data_length is checked at line 1723-1724: it must be <= CIFSMaxBufSize AND <= count (the requested byte count). CIFSMaxBufSize is a compile-time constant bounding the source buffer, and count is the caller-supplied maximum. A counterexample would require data_length > CIFSMaxBufSize or data_length > count — both are blocked by the guard. The destination buffer *buf was allocated by the caller for at least 'count' bytes, so the destination side is also covered. No counterexample exists that passes both guards and still overflows.

Finding #2 — Category A — BUG oob_read

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 1731
Taint snippetpReadData = (char *) (&pSMBr->hdr.Protocol) +
Tainted varpReadData
Sinkmemcpy() line 1738 (arg 1, role=pointer)
Sink snippetmemcpy(*buf, pReadData, data_length);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: KASAN: slab-out-of-bounds in CIFSSMBRead — a malicious server sets DataOffset to a very large value, pushing pReadData beyond the response buffer; the subsequent memcpy reads out-of-bounds kernel heap memory into the caller's buffer.
Fix: Before computing pReadData, validate that DataOffset is within the received response buffer: the offset from &pSMBr->hdr.Protocol to the end of the buffer must be at least DataOffset + data_length. Concretely: u16 data_offset = le16_to_cpu(pSMBr->DataOffset); if (data_offset < sizeof(READ_RSP) - offsetof(READ_RSP, hdr.Protocol) || (size_t)data_offset + data_length > rsp_iov.iov_len - offsetof(READ_RSP, hdr.Protocol)) { rc = -EIO; *nbytes = 0; } else { pReadData = (char *)(&pSMBr->hdr.Protocol) + data_offset; ... }
CVE pattern: SMB response DataOffset out-of-bounds read — similar in structure to CVE-2019-5544 / historical CIFS DataOffset validation issues
The function validates the response with validate_t2() and checks BCC >= 2, but does not validate that DataOffset is within the response buffer bounds before computing data_start, nor does it validate that DataCount is within the actual received data. Finding #1 (data_start OOB pointer) is a real concern but the actual dangerous sink in cifs_strndup_from_utf16 uses 'count' (maxlen) as the bound for cifs_utf16_bytes/kstrndup, not data_start itself as a size — so data_start affects the src pointer, not allocation size directly. Finding #2 (count used as maxlen) is genuine: a server-supplied DataCount is passed as maxlen to cifs_strndup_from_utf16 which uses it in cifs_utf16_bytes and kstrndup without verifying it fits within the actual received buffer, but the allocation itself is bounded by the actual UTF-16 byte scan result, so the risk is an OOB read of src rather than an oversized allocation.

Finding #1 — Category B — cross-function via cifs_strndup_from_utf16() — BUG oob_read

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 2939
Taint snippetdata_start = ((char *) &pSMBr->hdr.Protocol) +
Tainted vardata_start
Call siteline 2948 — passes data_start to cifs_strndup_from_utf16()
Call snippet*symlinkinfo = cifs_strndup_from_utf16(data_start,
Sink (in callee)kmalloc() line 341 (arg 0, role=size)
Sink snippetdst = kmalloc(len, GFP_KERNEL);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds or kernel panic if server supplies a DataOffset that points outside the response buffer, causing data_start to point to unrelated memory that is then scanned by cifs_utf16_bytes or kstrndup
Fix: After computing data_start, validate that data_start + count does not exceed the end of the received response buffer (pSMBr + bytes_returned or similar bound). Reject the response with -EIO if the range is out of bounds.
CVE pattern: CVE-2022-NNNN style DataOffset OOB — server-controlled offset used without bounds check before pointer arithmetic on response buffer

Finding #2 — Category B — cross-function via cifs_strndup_from_utf16() — BUG oob_read

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 2937
Taint snippetu16 count = le16_to_cpu(pSMBr->t2.DataCount);
Tainted varcount
Call siteline 2948 — passes count to cifs_strndup_from_utf16()
Call snippet*symlinkinfo = cifs_strndup_from_utf16(data_start,
Sink (in callee)kmalloc() line 341 (arg 0, role=size)
Sink snippetdst = kmalloc(len, GFP_KERNEL);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds when cifs_utf16_bytes or kstrndup reads up to 'count' bytes from data_start, which may exceed the actual received data if count > actual data in buffer
Fix: Validate that count (DataCount) does not exceed bytes_returned minus the offset to data_start (i.e., the actual data region in the response). Clamp or reject with -EIO if count > available bytes. The check 'get_bcc(&pSMBr->hdr) < 2' is insufficient — it only ensures BCC is at least 2, not that DataCount fits within the buffer.
CVE pattern: Missing DataCount bounds validation against actual response buffer size in CIFS/SMB symlink query — similar to several historical CIFS CVEs involving unchecked server-supplied counts

SMBOldQFSInfo() — fs/smb/client/cifssmb.c BUG confidence=high

The function validates that BCC >= 18 (line 4954) but does NOT validate that data_offset (server-supplied from pSMBr->t2.DataOffset) places the FILE_SYSTEM_ALLOC_INFO struct within the actual received packet. A malicious or buggy server can supply a large DataOffset that pushes response_data beyond the packet buffer, causing out-of-bounds reads. The BCC check only validates the byte count field, not the DataOffset field. validate_t2() is called but its postcondition does not guarantee DataOffset+sizeof(FILE_SYSTEM_ALLOC_INFO) <= packet_end. Counterexample: data_offset = 0xFFFF would place response_data far beyond the packet, yet the only guard is BCC >= 18.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4958
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->BytesPerSector line 4965
Sink snippetle16_to_cpu(response_data->BytesPerSector) *
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in SMBOldQFSInfo when accessing response_data->BytesPerSector; kernel crash or info disclosure from heap memory beyond the received SMB response buffer
Fix: After computing response_data, verify that (char*)response_data + sizeof(FILE_SYSTEM_ALLOC_INFO) <= (char*)&pSMBr->hdr.Protocol + get_bcc(&pSMBr->hdr) + sizeof(pSMBr->hdr) (i.e., within the packet bounds). Also validate data_offset is not smaller than the header size. For example: if (data_offset > bytes_returned - sizeof(*response_data)) { rc = -EIO; goto done; }
CVE pattern: SMB transaction2 DataOffset out-of-bounds read — similar pattern to CVE-2012-1090 style CIFS DataOffset OOB

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4958
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->SectorsPerAllocationUnit line 4966
Sink snippetle32_to_cpu(response_data->
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in SMBOldQFSInfo when accessing response_data->SectorsPerAllocationUnit; kernel crash or info disclosure
Fix: Same fix as finding #1: validate data_offset + sizeof(FILE_SYSTEM_ALLOC_INFO) <= received packet length before dereferencing response_data.
CVE pattern: SMB transaction2 DataOffset out-of-bounds read

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4958
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->TotalAllocationUnits line 4976
Sink snippetle32_to_cpu(response_data->TotalAllocationUnits);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in SMBOldQFSInfo when accessing response_data->TotalAllocationUnits; kernel crash or info disclosure
Fix: Same fix as finding #1.
CVE pattern: SMB transaction2 DataOffset out-of-bounds read

Finding #4 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 4958
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted varresponse_data
Pointer derefresponse_data->FreeAllocationUnits line 4978
Sink snippetle32_to_cpu(response_data->FreeAllocationUnits);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in SMBOldQFSInfo when accessing response_data->FreeAllocationUnits; kernel crash or info disclosure
Fix: Same fix as finding #1.
CVE pattern: SMB transaction2 DataOffset out-of-bounds read

cifs_create_reparse_inode() — fs/smb/client/cifssmb.c MIXED confidence=medium

The xattr_iov data appears to be kernel-constructed for EA setting during reparse point creation, making finding #1 likely a false positive. However, CIFSSMBSetEA() has an explicitly acknowledged missing bounds check (the 'BB' comment) for ea_value_len against the negotiated SMB buffer size, making finding #2 a real concern if the EA value length can be attacker-influenced.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 3156
Taint snippetea = (struct smb2_file_full_ea_info *)((u8 *)ea +
Tainted varea
Pointer derefea->next_entry_offset line 3157
Sink snippetle32_to_cpu(ea->next_entry_offset));
Possibly guardedno
Dismissed: The xattr_iov is kernel-constructed (passed from internal reparse point creation logic, not a server response). The next_entry_offset field is written by the kernel when constructing the EA context. The check for == 0 is sufficient for kernel-controlled data. This is a false positive because the EA context structure is built locally, not received from the server.

Finding #2 — Category B — cross-function via CIFSSMBSetEA() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 3144
Taint snippetrc = CIFSSMBSetEA(xid,
Tainted varle16_to_cpu(ea->ea_value_length)
Call siteline 3144 — passes le16_to_cpu(ea->ea_value_length) to CIFSSMBSetEA()
Call snippetrc = CIFSSMBSetEA(xid,
Sink (in callee)memcpy() line 6390 (arg 2, role=size)
Sink snippetmemcpy(parm_data->list.name + name_len + 1,
Possibly guardedno
Dismissed: ea->ea_value_length comes from xattr_iov which is kernel-constructed data passed in by the caller, not a server response. The memcpy in CIFSSMBSetEA() has an acknowledged TODO comment about adding a length check, but since the EA value length is kernel-controlled (not server-supplied), this is not an exploitable vulnerability from a network attacker perspective. The missing bound check against the negotiated SMB buffer size is a robustness issue but not a security bug in this call path. Counterexample: no concrete counterexample possible since the caller controls ea_value_length.

cifs_do_get_acl() — fs/smb/client/cifssmb.c MIXED confidence=medium

Finding #1 concerns data_offset used to compute src pointer without validating it against the received buffer size, which could produce an out-of-bounds pointer before cifs_to_posix_acl() even begins. Finding #2 is a false positive: the count used in ace_array[count] is cifs_acl->access_entry_count (a callee-local variable), and it IS validated against size_of_data_area before the subscript, making the access safe.

Finding #1 — Category C — cross-function via cifs_to_posix_acl() — BUG oob_read

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 3521
Taint snippet__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Tainted vardata_offset
Call siteline 3523 — passes data_offset to cifs_to_posix_acl()
Call snippetrc = cifs_to_posix_acl(acl,
Subscript (in callee)[] line 3343
Sink snippetpACE = &cifs_acl->ace_array[count];
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds or kernel panic when dereferencing src pointer derived from unchecked server-supplied DataOffset
Fix: Validate data_offset before use: check that data_offset + count <= total response buffer size (e.g., bytes_returned or get_bcc result), rejecting the response if the data area falls outside the received buffer.
CVE pattern: CVE-2022-NNNN style DataOffset OOB — unchecked DataOffset in SMB/CIFS transaction2 response

Finding #2 — Category C — cross-function via cifs_to_posix_acl() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 3522
Taint snippet__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Tainted varcount
Call siteline 3523 — passes count to cifs_to_posix_acl()
Call snippetrc = cifs_to_posix_acl(acl,
Subscript (in callee)[] line 3343
Sink snippetpACE = &cifs_acl->ace_array[count];
Possibly guardedno
Dismissed: The scanner incorrectly attributes the subscript to the DataCount parameter. Inside cifs_to_posix_acl(), the array subscript &cifs_acl->ace_array[count] uses a local 'count' derived from cifs_acl->access_entry_count, which is validated against size_of_data_area (the DataCount) before the subscript. The check 'if (size_of_data_area < size) return -EINVAL' at line 3333 covers this. No counterexample possible: if count*sizeof(cifs_posix_ace)+header > size_of_data_area, the function returns -EINVAL before reaching line 3343.

cifs_query_reparse_point() — fs/smb/client/cifssmb.c BUG confidence=medium

The function validates data_offset <= 512 and the original data_count <= 2048, and checks start < end. However, it then reassigns data_count from io_rsp->ByteCount and checks ByteCount >= sizeof(*buf), but never verifies that start + sizeof(*buf) <= end (the BCC-derived packet boundary). A server could supply a small BCC but large ByteCount, causing buf->ReparseDataLength to be read beyond packet bounds.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 3032
Taint snippetdata_offset = le32_to_cpu(io_rsp->DataOffset);
Tainted varbuf
Pointer derefbuf->ReparseDataLength line 3072
Sink snippetdata_count < le16_to_cpu(buf->ReparseDataLength) + len) {
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in cifs_query_reparse_point when accessing buf->ReparseDataLength beyond packet boundary
Fix: Before accessing buf->ReparseDataLength, verify that (start + sizeof(*buf)) <= end, i.e., add: if ((end - start) < (ptrdiff_t)len) { rc = -EIO; goto error; }
CVE pattern: CVE-2022-NNNN style DataOffset OOB — server-controlled offset used to derive pointer without full size validation against packet boundary

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 3032
Taint snippetdata_offset = le32_to_cpu(io_rsp->DataOffset);
Tainted varbuf
Pointer derefbuf->ReparseDataLength line 3074
Sink snippetdata_count, le16_to_cpu(buf->ReparseDataLength) + len);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in cifs_query_reparse_point when accessing buf->ReparseDataLength in error trace path beyond packet boundary
Fix: Same fix as finding #1: validate (end - start) >= sizeof(*buf) before dereferencing buf fields.
CVE pattern: CVE-2022-NNNN style DataOffset OOB

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 3032
Taint snippetdata_offset = le32_to_cpu(io_rsp->DataOffset);
Tainted varbuf
Pointer derefbuf->ReparseTag line 3078
Sink snippet*tag = le32_to_cpu(buf->ReparseTag);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in cifs_query_reparse_point when accessing buf->ReparseTag beyond packet boundary
Fix: Same fix: ensure (end - start) >= sizeof(*buf) before line 3069. Also the check at 3071 using ByteCount rather than the BCC-derived boundary must be supplemented with an end-boundary check.
CVE pattern: CVE-2022-NNNN style DataOffset OOB

cifs_to_posix_acl() — fs/smb/client/cifssmb.c FP confidence=medium

The function validates buffer bounds before actual memory reads occur. The subscript use at line 3343 is pointer arithmetic (address computation), not a memory read. The bounds check at line 3347 covers the full range (sizeof(cifs_posix_acl) + access_entry_count*ace_size + default_entry_count*ace_size) before any data is actually read from pACE in the FOREACH loop. However, there is a latent integer overflow risk in the size calculation with large server-supplied counts that could theoretically cause the bounds check to pass incorrectly.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 3339
Taint snippetcount = le16_to_cpu(cifs_acl->access_entry_count);
Tainted varcount
Subscript[] line 3343
Sink snippetpACE = &cifs_acl->ace_array[count];
Possibly guardedno
Dismissed: The pointer arithmetic at line 3343 is address computation, not a memory read. Actual memory reads only occur in the FOREACH loop at line 3359, which is after the bounds check at line 3347 validates the full buffer range. No counterexample found where the bounds check passes but OOB access occurs, given non-overflowing arithmetic. The check at line 3347 comes after pACE is computed but before pACE is dereferenced, so it is sufficient for memory safety. A potential integer overflow in the size multiplication with very large server-supplied counts (e.g., count=65535) could in theory defeat the check, but this is a separate concern from the flagged subscript issue.

parse_dfs_referrals() — fs/smb/client/misc.c FP confidence=high

parse_dfs_referrals() has solid validation discipline: it checks rsp_size against sizeof(*rsp), then against sizeof(*rsp)+num_referrals*sizeof(REFERRAL3), bounds-checks DfsPathOffset and NetworkAddressOffset against data_end before dereferencing, and bounds-checks path_consumed against search_name_utf16_len before passing to cifs_utf16_bytes(). All three flagged flows are protected by guards that are tight enough to prevent exploitation.

Finding #1 — Category F — cross-function via cifs_utf16_bytes() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 757
Taint snippetpath_consumed = le16_to_cpu(rsp->PathConsumed);
Tainted varpath_consumed
Call siteline 774 — passes path_consumed to cifs_utf16_bytes()
Call snippetnode->path_consumed = cifs_utf16_bytes(tmp, path_consumed,
Loopfor_loop line 299
Sink snippetfor (i = 0; i < maxwords; i++) {
Possibly guardedyes (heuristic)
Dismissed: path_consumed is validated at line 762: it must not exceed search_name_utf16_len (= search_name_len*2+2), and tmp is allocated with exactly search_name_utf16_len bytes. cifs_utf16_bytes iterates up to path_consumed/2 words of tmp, which is within the allocated size. No counterexample can be constructed: any path_consumed > search_name_utf16_len causes early return before the call.

Finding #2 — Category B — cross-function via cifs_strndup_from_utf16() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 794
Taint snippettemp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
Tainted vartemp
Call siteline 796 — passes temp to cifs_strndup_from_utf16()
Call snippetnode->path_name = cifs_strndup_from_utf16(temp, max_len,
Sink (in callee)kmalloc() line 341 (arg 0, role=size)
Sink snippetdst = kmalloc(len, GFP_KERNEL);
Possibly guardedno
Dismissed: The scanner misattributes the taint: temp is a pointer derived from ref+DfsPathOffset, not a size. The actual kmalloc size inside cifs_strndup_from_utf16 is computed by cifs_utf16_bytes scanning at most max_len bytes (= data_end - temp, always non-negative after the offset guard). The guard at line 790 ensures offset does not exceed data_end - ref, so temp <= data_end and max_len >= 0 and bounded by rsp_size.

Finding #3 — Category B — cross-function via cifs_strndup_from_utf16() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 794
Taint snippettemp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
Tainted varmax_len
Call siteline 796 — passes max_len to cifs_strndup_from_utf16()
Call snippetnode->path_name = cifs_strndup_from_utf16(temp, max_len,
Sink (in callee)kmalloc() line 341 (arg 0, role=size)
Sink snippetdst = kmalloc(len, GFP_KERNEL);
Possibly guardedno
Dismissed: max_len = data_end - temp is bounded by rsp_size (an externally validated response size parameter). The guard at line 790 ensures DfsPathOffset <= data_end - ref, making max_len non-negative and at most rsp_size. cifs_utf16_bytes uses max_len only as an iteration bound over a received buffer, and the kmalloc size is derived from actual content length, not max_len directly. No counterexample exists given these constraints.

cnvrtDosUnixTm() — fs/smb/client/netmisc.c FP confidence=high

The function processes server-supplied DOS date/time fields. While the values are genuinely server-supplied (tainted), the code at lines 181-184 validates month with an explicit bounds check (month < 1 || month > 12) and then clamps it to [1,12] via clamp(). After the mandatory month -= 1 decrement at line 186, the index is guaranteed to be in [0,11], which is a valid range for total_days_of_prev_months. The static scanner incorrectly flagged this as unguarded; the clamp provides sufficient protection.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 164
Taint snippetu16 date = le16_to_cpu(le_date);
Tainted varmonth
Subscript[] line 187
Sink snippetdays = day + total_days_of_prev_months[month];
Possibly guardedno
Dismissed: The scanner marked this as 'Possibly guarded: no' but missed the clamp() call at line 183-184. After clamp(month, 1, 12), month is in [1,12]; after month -= 1, the array subscript is in [0,11]. No counterexample can be constructed: any server-supplied month value, whether 0, negative (impossible since u16 fields via sd->Month are unsigned), or >12, will be clamped before use. The array access is fully safe.

mknod_wsl() — fs/smb/client/reparse.c FP confidence=high

Both findings are false positives. Finding #1: cc = xattr_iov.iov_base is populated by wsl_set_xattrs(), a kernel-side builder function that constructs xattr data locally — DataLength is written by the kernel with cpu_to_le32(constant), so le32_to_cpu() recovers a locally-controlled value, not server-supplied data. Finding #2: cifs_free_open_info() calls memset(data, 0, sizeof(*data)) where the size argument is sizeof(*data), a compile-time constant derived from the struct type — the scanner incorrectly traced taint through the struct pointer to the sizeof operator, but sizeof is evaluated at compile time and is independent of any field value in the struct.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 703
Taint snippetlen = le32_to_cpu(cc->ctx.DataLength);
Tainted varlen
Sinkmemcpy() line 704 (arg 2, role=size)
Sink snippetmemcpy(data.wsl.eas, &cc->ea, len);
Possibly guardedno
Dismissed: cc is set from xattr_iov.iov_base, which is populated by wsl_set_xattrs() — a locally-constructed kernel buffer. The DataLength field is written by the kernel (cpu_to_le32 of a constant), not received from a server. le32_to_cpu() here is simply recovering a kernel-written value. This matches false positive pattern #1 (locally-written struct fields). No server-supplied data is involved.

Finding #2 — Category B — cross-function via cifs_free_open_info() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 696
Taint snippetdata = (struct cifs_open_info_data) {
Tainted vardata
Call siteline 715 — passes data to cifs_free_open_info()
Call snippetcifs_free_open_info(&data);
Sink (in callee)memset() line 490 (arg 2, role=size)
Sink snippetmemset(data, 0, sizeof(*data));
Possibly guardedno
Dismissed: The scanner traced taint from le32_to_cpu() at line 696 through the 'data' struct to the memset() in cifs_free_open_info(). However, memset(data, 0, sizeof(*data)) uses sizeof(*data) as its size argument — a compile-time constant representing the size of struct cifs_open_info_data. No tainted field value is used as the size. The scanner incorrectly identified sizeof(*data) as tainted because 'data' itself was considered tainted. This is a clear false positive due to taint propagation through a pointer that is then used only in sizeof().
parse_reparse_native_symlink() validates both offs and len against plen before calling smb2_parse_native_symlink(). The check 'offs + 20 > plen || offs + len + 20 > plen' ensures the buffer pointer and length are within bounds. Inside smb2_parse_native_symlink(), the allocation sizes (abs_path_len, smb_target_len) are derived from strlen() of strings produced by UTF-16 conversion of the bounded buffer — they are not directly server-controlled sizes. The scanner is tracking taint through multiple transformations and incorrectly flagging allocations whose sizes are bounded by strlen() of processed strings. No counterexample can be constructed: the guards are tight enough that no combination of offs/len values can pass the check and cause OOB.

Finding #1 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1013
Taint snippetoffs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varoffs
Call siteline 1021 — passes offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)kmalloc() line 939 (arg 0, role=size_mul_overflow)
Sink snippetlinux_target = kmalloc(symlinkroot_len + 1 + abs_path_len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: offs is validated: offs+20<=plen and offs+len+20<=plen. In callee, abs_path_len=strlen(abs_path)+1 is derived from strlen of UTF-16-converted string of bounded length len, so kmalloc size is safe. No counterexample exists.

Finding #2 — Category A — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 1013
Taint snippetoffs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varoffs
Call siteline 1021 — passes offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)memcpy() line 944 (arg 0, role=pointer)
Sink snippetmemcpy(linux_target, symroot, symlinkroot_len);
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 944 copies symroot (local config string) into linux_target which was allocated to fit it. offs taint does not affect this operation's safety. Bounds check is sufficient.

Finding #3 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1013
Taint snippetoffs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varoffs
Call siteline 1021 — passes offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)memcpy() line 946 (arg 2, role=size)
Sink snippetmemcpy(linux_target + symlinkroot_len + 1, abs_path, abs_path_len);
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 946 uses abs_path_len=strlen(abs_path)+1 as size and linux_target was allocated with symlinkroot_len+1+abs_path_len bytes. Size matches allocation. No OOB possible.

Finding #4 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1013
Taint snippetoffs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varoffs
Call siteline 1021 — passes offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)kmalloc() line 964 (arg 0, role=size_mul_overflow)
Sink snippetlinux_target = kmalloc(levels*3 + smb_target_len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: kmalloc at line 964 uses levels*3+smb_target_len where smb_target_len=strlen(smb_target)+1. levels is bounded by strlen(full_path) which is a local kernel path, not server data. No counterexample exists.

Finding #5 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1013
Taint snippetoffs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varoffs
Call siteline 1021 — passes offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)memcpy() line 974 (arg 2, role=size)
Sink snippetmemcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 974 copies smb_target+1 of size smb_target_len into linux_target+levels*3; allocation was levels*3+smb_target_len. Sizes match exactly. No OOB possible.

Finding #6 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1014
Taint snippetlen = le16_to_cpu(sym->SubstituteNameLength);
Tainted varlen
Call siteline 1021 — passes len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)kmalloc() line 939 (arg 0, role=size_mul_overflow)
Sink snippetlinux_target = kmalloc(symlinkroot_len + 1 + abs_path_len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: len is validated: offs+len+20<=plen ensures the UTF-16 string of length len is within the buffer. abs_path_len from strlen of converted string is bounded by len. kmalloc size is safe.

Finding #7 — Category A — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 1014
Taint snippetlen = le16_to_cpu(sym->SubstituteNameLength);
Tainted varlen
Call siteline 1021 — passes len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)memcpy() line 944 (arg 0, role=pointer)
Sink snippetmemcpy(linux_target, symroot, symlinkroot_len);
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 944 copies symroot into linux_target; len taint does not affect this operation. linux_target was allocated to contain symroot. Safe.

Finding #8 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1014
Taint snippetlen = le16_to_cpu(sym->SubstituteNameLength);
Tainted varlen
Call siteline 1021 — passes len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)memcpy() line 946 (arg 2, role=size)
Sink snippetmemcpy(linux_target + symlinkroot_len + 1, abs_path, abs_path_len);
Possibly guardedyes (heuristic)
Dismissed: abs_path_len=strlen(abs_path)+1 is bounded by the UTF-16 decoded string length which is bounded by len. memcpy size matches strlen result. Allocation matches. No counterexample.

Finding #9 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1014
Taint snippetlen = le16_to_cpu(sym->SubstituteNameLength);
Tainted varlen
Call siteline 1021 — passes len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)kmalloc() line 964 (arg 0, role=size_mul_overflow)
Sink snippetlinux_target = kmalloc(levels*3 + smb_target_len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: smb_target_len=strlen(smb_target)+1 bounded by decoded string length. levels from strlen(full_path) is local. kmalloc size safe. No counterexample.

Finding #10 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1014
Taint snippetlen = le16_to_cpu(sym->SubstituteNameLength);
Tainted varlen
Call siteline 1021 — passes len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(&data->symlink_target,
Sink (in callee)memcpy() line 974 (arg 2, role=size)
Sink snippetmemcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 974 size is smb_target_len=strlen(smb_target)+1 and allocation was levels*3+smb_target_len. Destination has enough space. No OOB possible.

parse_reparse_nfs() — fs/smb/client/reparse.c FP confidence=high

parse_reparse_nfs() has layered validation: it checks ReparseDataLength >= sizeof(InodeType), subtracts InodeType size, then for the symlink case checks len > 0 and len is even, plus a UniStrnlen null-byte check before calling cifs_strndup_from_utf16(). The len value passed to cifs_strndup_from_utf16() as maxlen is server-supplied but properly guarded. Inside cifs_strndup_from_utf16(), the allocation size is computed from cifs_utf16_bytes() which is bounded by maxlen, not exceeding it, so no integer overflow or undersized allocation is possible.

Finding #1 — Category B — cross-function via cifs_strndup_from_utf16() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 748
Taint snippetlen = le16_to_cpu(buf->ReparseDataLength);
Tainted varlen
Call siteline 771 — passes len to cifs_strndup_from_utf16()
Call snippetdata->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,
Sink (in callee)kmalloc() line 341 (arg 0, role=size)
Sink snippetdst = kmalloc(len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: After subtracting sizeof(InodeType) and verifying len > 0 and len is even, the remaining len is a valid maxlen for cifs_strndup_from_utf16(). Inside that callee, kmalloc size = cifs_utf16_bytes(..., maxlen, ...) + nls_nullsize, where cifs_utf16_bytes scans at most maxlen bytes of UTF-16 and returns a byte count for the UTF-8 representation. No counterexample found: any len passing the guards (even, >= 2, <= 65527 after subtraction) yields a valid kmalloc size well within int and size_t ranges. The scanner flagged server-supplied taint flowing into kmalloc, but the intermediate guards are sufficient.
The function properly validates len > data_offset before computing symname_utf8_len. Since ReparseDataLength is a u16 (max 65535), symname_utf8_len is at most ~65530, and multiplying by 2 gives at most ~131060 — well within int and size_t ranges, so no integer overflow is possible. The symname_utf16 pointer taint is a tracker artifact (it's a locally-allocated buffer). The symname_utf16_len value is bounded by utf8s_to_utf16s() output constraints and the u16 source limit. All three findings are false positives.

Finding #1 — Category B — INTEGER OVERFLOW — false positive

CategoryCat B — integer overflow: symname_utf8_len * 2
Taint sourcele16_to_cpu() line 1033
Taint snippetint len = le16_to_cpu(buf->ReparseDataLength);
Tainted varsymname_utf8_len
Overflow exprsymname_utf8_len * 2
Safe fixkmalloc_array() or check_mul_overflow()
Sinkkzalloc() line 1066 (arg 0, role=size_mul_overflow)
Sink snippetsymname_utf16 = kzalloc(symname_utf8_len * 2, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: symname_utf8_len derives from a u16 field (max 65535). After the guard 'len > data_offset', symname_utf8_len is at most 65535. The multiplication symname_utf8_len * 2 in int arithmetic yields at most 131070, which cannot overflow a 32-bit int or produce a nonsensical size_t. Counterexample: no u16 value can make this overflow. False positive.

Finding #2 — Category B — cross-function via cifs_strndup_from_utf16() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1033
Taint snippetint len = le16_to_cpu(buf->ReparseDataLength);
Tainted varsymname_utf16
Call siteline 1078 — passes symname_utf16 to cifs_strndup_from_utf16()
Call snippetdata->symlink_target = cifs_strndup_from_utf16((u8 *)symname_utf16,
Sink (in callee)kmalloc() line 341 (arg 0, role=size)
Sink snippetdst = kmalloc(len, GFP_KERNEL);
Possibly guardedno
Dismissed: symname_utf16 is a locally allocated pointer (result of kzalloc). The taint tracker incorrectly propagates taint to the pointer variable itself. The pointer points to kernel-controlled memory. This is a taint tracker artifact — false positive.

Finding #3 — Category B — cross-function via cifs_strndup_from_utf16() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1033
Taint snippetint len = le16_to_cpu(buf->ReparseDataLength);
Tainted varsymname_utf16_len
Call siteline 1078 — passes symname_utf16_len to cifs_strndup_from_utf16()
Call snippetdata->symlink_target = cifs_strndup_from_utf16((u8 *)symname_utf16,
Sink (in callee)kmalloc() line 341 (arg 0, role=size)
Sink snippetdst = kmalloc(len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: symname_utf16_len comes from utf8s_to_utf16s() return value (number of u16 items written, bounded by the output buffer size symname_utf8_len), then doubled. Since symname_utf8_len ≤ 65535, symname_utf16_len ≤ 131070. In cifs_strndup_from_utf16, the resulting kmalloc size is bounded by cifs_utf16_bytes() output (≤ maxlen) plus nls_nullsize. No overflow possible. Counterexample: no u16 source value produces an overflow. False positive.

map_smb_to_linux_error() — fs/smb/client/smb1maperror.c FP confidence=high

The taint propagation is incorrect. `map` is a pointer returned by `search_ntstatus_to_dos_map()`, a lookup function that searches a kernel-internal static table using the server-supplied NT status code as a key. The returned pointer points to kernel static data (compile-time constants), not to the server's network buffer. The server controls only which table entry is selected (or whether NULL is returned), not the contents of `dos_class` or `dos_code` within those entries. The truncation of these kernel-constant values to u8/u16 is intentional and safe because the table entries were designed with those field widths in mind.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele32_to_cpu() line 129
Taint snippetsmberrclass = map->dos_class;
Tainted varsmberrclass
Truncationline 129: 32 → 8-bit u8
Sink snippetsmberrclass = map->dos_class;
Possibly guardedno
Dismissed: map->dos_class comes from the kernel's own static ntstatus_to_dos_map[] table, not from the server's network packet. The server supplied only the lookup key (NT status code); the table entry contents are kernel-defined compile-time constants. Taint propagation through the lookup function's return value is a false positive. The dos_class field in the static table is defined to fit in a u8.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele32_to_cpu() line 130
Taint snippetsmberrcode = map->dos_code;
Tainted varsmberrcode
Truncationline 130: 32 → 16-bit u16
Sink snippetsmberrcode = map->dos_code;
Possibly guardedno
Dismissed: map->dos_code comes from the kernel's own static ntstatus_to_dos_map[] table, not from the server's network packet. Same reasoning as finding #1: the server controls only the lookup key, not the table entry values. The dos_code field is a kernel-defined constant intended to fit in a u16. False positive.

is_valid_oplock_break() — fs/smb/client/smb1misc.c BUG confidence=high

The function attempts to validate data_offset before constructing pnotify, but the check at line 88-93 has an integer underflow vulnerability: if len < sizeof(struct file_notify_information), the subtraction wraps around (unsigned arithmetic), making the guard trivially pass for any data_offset. Additionally, the pointer base (&hdr.Protocol) is 4 bytes into the buffer, so even a correct len-based check would need to account for that offset.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 86
Taint snippetdata_offset = le32_to_cpu(pSMBr->DataOffset);
Tainted varpnotify
Pointer derefpnotify->FileName line 97
Sink snippetpnotify->FileName, pnotify->Action);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in is_valid_oplock_break when accessing pnotify->FileName or pnotify->Action with a crafted DataOffset; possible kernel info disclosure or panic
Fix: Before the data_offset check, verify that len >= sizeof(struct file_notify_information) to prevent unsigned underflow. Then check data_offset <= len - sizeof(struct file_notify_information). Also account for the 4-byte offset of &hdr.Protocol from the buffer start: ensure data_offset + sizeof(*pnotify) <= total_read - offsetof(smb_hdr, Protocol). Use explicit size_t arithmetic with overflow checks.
CVE pattern: SMB response DataOffset integer underflow / OOB read pattern, similar to CVE-2020-0796 style offset validation bugs in SMB parsing

cifs_query_path_info() — fs/smb/client/smb1ops.c ERROR confidence=low

Finding #1 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_data line 665
Sink snippet&ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
Possibly guardedno

Finding #2 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->next_entry_offset line 668
Sink snippetea->next_entry_offset = cpu_to_le32(0);
Possibly guardedno

Finding #3 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->flags line 669
Sink snippetea->flags = 0;
Possibly guardedno

Finding #4 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_name_length line 670
Sink snippetea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
Possibly guardedno

Finding #5 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_value_length line 671
Sink snippetea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_MODE_SIZE);
Possibly guardedno

Finding #6 — Category A — unanalyzed

CategoryCat A — server offset → pointer → memory op
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Sinkmemcpy() line 672 (arg 0, role=pointer)
Sink snippetmemcpy(&ea->ea_data[0], SMB2_WSL_XATTR_MODE, SMB2_WSL_XATTR_NAME_LEN + 1);
Possibly guardedno

Finding #7 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_data line 672
Sink snippetmemcpy(&ea->ea_data[0], SMB2_WSL_XATTR_MODE, SMB2_WSL_XATTR_NAME_LEN + 1);
Possibly guardedno

Finding #8 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->next_entry_offset line 701
Sink snippetnext = le32_to_cpu(ea->next_entry_offset);
Possibly guardedno

Finding #9 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_value_length line 703
Sink snippetif (le16_to_cpu(ea->ea_value_length)) {
Possibly guardedno

Finding #10 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->next_entry_offset line 704
Sink snippetea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
Possibly guardedno

Finding #11 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_name_length line 705
Sink snippetea->ea_name_length + 1 +
Possibly guardedno

Finding #12 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_value_length line 706
Sink snippetle16_to_cpu(ea->ea_value_length), 4));
Possibly guardedno

Finding #13 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 707
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_data line 711
Sink snippet&ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
Possibly guardedno

Finding #14 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 707
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->next_entry_offset line 714
Sink snippetea->next_entry_offset = cpu_to_le32(0);
Possibly guardedno

Finding #15 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 707
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->flags line 715
Sink snippetea->flags = 0;
Possibly guardedno

Finding #16 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 707
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_name_length line 716
Sink snippetea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
Possibly guardedno

Finding #17 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 707
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_value_length line 717
Sink snippetea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_DEV_SIZE);
Possibly guardedno

Finding #18 — Category A — unanalyzed

CategoryCat A — server offset → pointer → memory op
Taint sourcele32_to_cpu() line 707
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Sinkmemcpy() line 718 (arg 0, role=pointer)
Sink snippetmemcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1);
Possibly guardedno

Finding #19 — Category E — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 707
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Pointer derefea->ea_data line 718
Sink snippetmemcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1);
Possibly guardedno

Finding #20 — Category E — cross-function via CIFSSMBQAllEAs() — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Call siteline 664 — passes ea to CIFSSMBQAllEAs()
Call snippetrc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
Pointer derefea-> line 6214
Sink snippetlist_len = le32_to_cpu(ea_response_data->list_len);
Possibly guardedno

Finding #21 — Category E — cross-function via CIFSSMBQAllEAs() — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Call siteline 664 — passes ea to CIFSSMBQAllEAs()
Call snippetrc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
Pointer derefea-> line 6236
Sink snippettemp_fea = &ea_response_data->list;
Possibly guardedyes (heuristic)

Finding #22 — Category F — cross-function via CIFSSMBQAllEAs() — unanalyzed

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Call siteline 664 — passes ea to CIFSSMBQAllEAs()
Call snippetrc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
Loopwhile_loop line 6238
Sink snippetwhile (list_len > 0) {
Possibly guardedyes (heuristic)

Finding #23 — Category E — cross-function via CIFSSMBQAllEAs() — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Call siteline 664 — passes ea to CIFSSMBQAllEAs()
Call snippetrc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
Pointer derefea-> line 6251
Sink snippetname_len = temp_fea->name_len;
Possibly guardedno

Finding #24 — Category E — cross-function via CIFSSMBQAllEAs() — unanalyzed

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Call siteline 664 — passes ea to CIFSSMBQAllEAs()
Call snippetrc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
Pointer derefea-> line 6252
Sink snippetvalue_len = le16_to_cpu(temp_fea->value_len);
Possibly guardedno

Finding #25 — Category B — cross-function via CIFSSMBQAllEAs() — unanalyzed

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Call siteline 664 — passes ea to CIFSSMBQAllEAs()
Call snippetrc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
Sink (in callee)memcmp() line 6262 (arg 2, role=size)
Sink snippetmemcmp(ea_name, temp_ptr, name_len) == 0) {
Possibly guardedyes (heuristic)

Finding #26 — Category B — cross-function via CIFSSMBQAllEAs() — unanalyzed

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Call siteline 664 — passes ea to CIFSSMBQAllEAs()
Call snippetrc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
Sink (in callee)memcpy() line 6271 (arg 2, role=size)
Sink snippetmemcpy(EAData, temp_ptr, value_len);
Possibly guardedyes (heuristic)

Finding #27 — Category B — cross-function via CIFSSMBQAllEAs() — unanalyzed

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 661
Taint snippetea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
Tainted varea
Call siteline 664 — passes ea to CIFSSMBQAllEAs()
Call snippetrc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
Sink (in callee)memcpy() line 6280 (arg 2, role=size)
Sink snippetmemcpy(EAData, temp_ptr, name_len);
Possibly guardedyes (heuristic)

coalesce_t2() — fs/smb/client/smb1transport.c BUG confidence=high

coalesce_t2() reads DataOffset and DataCount from server-supplied SMB T2 response buffers without validating that the resulting pointer arithmetic stays within the actual allocated buffer boundaries. The checks present (remaining < 0, total_in_tgt > USHRT_MAX, byte_count > CIFSMaxBufSize) do not constrain DataOffset values, so crafted server responses can cause out-of-bounds reads and writes via memcpy.

Finding #1 — Category B — BUG oob_read

CategoryCat B — server value → size/alloc argument
Taint sourceget_unaligned_le16() line 370
Taint snippettotal_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
Tainted vartotal_in_src
Sinkmemcpy() line 416 (arg 2, role=size)
Sink snippetmemcpy(data_area_of_tgt, data_area_of_src, total_in_src);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: KASAN: slab-out-of-bounds in coalesce_t2 reading from second_buf beyond its allocation; kernel panic or info disclosure
Fix: Validate that DataOffset + DataCount from the source buffer does not exceed the actual received PDU size of second_buf before computing data_area_of_src and calling memcpy. Also validate total_in_src against the destination remaining capacity independently of the BCC/smbCalcSize check.
CVE pattern: SMB DataOffset out-of-bounds read, similar in class to CVE-2011-2524 style SMB response parsing bugs

Finding #2 — Category A — BUG oob_write

CategoryCat A — server offset → pointer → memory op
Taint sourceget_unaligned_le16() line 375
Taint snippetdata_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
Tainted vardata_area_of_tgt
Sinkmemcpy() line 416 (arg 0, role=pointer)
Sink snippetmemcpy(data_area_of_tgt, data_area_of_src, total_in_src);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: KASAN: slab-out-of-bounds write in coalesce_t2; heap corruption leading to kernel panic or privilege escalation
Fix: Validate that DataOffset (from target) + DataCount (from target) does not exceed the target buffer's allocated size (CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) before computing data_area_of_tgt. The smbCalcSize check at line 408 fires after put_bcc modifies the header but does not directly validate DataOffset.
CVE pattern: SMB DataOffset OOB write in coalesce path

Finding #3 — Category A — BUG oob_read

CategoryCat A — server offset → pointer → memory op
Taint sourceget_unaligned_le16() line 379
Taint snippetdata_area_of_src = (char *)&pSMBs->hdr.Protocol +
Tainted vardata_area_of_src
Sinkmemcpy() line 416 (arg 1, role=pointer)
Sink snippetmemcpy(data_area_of_tgt, data_area_of_src, total_in_src);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: KASAN: slab-out-of-bounds read in coalesce_t2 when copying from source buffer; kernel crash or information disclosure
Fix: Validate that DataOffset from the source SMB header does not cause data_area_of_src to point outside the received second_buf. Specifically: check that DataOffset <= (received_pdu_len - DataCount) before using these fields to compute data_area_of_src.
CVE pattern: SMB T2 secondary response DataOffset OOB read
smb2_parse_symlink_response performs explicit bounds validation of sub_offs+sub_len and print_offs+print_len against the iov buffer before calling the callee. Inside smb2_parse_native_symlink(), the tainted buf/len parameters are consumed by cifs_strndup_from_utf16() (a bounded conversion), producing a kernel-allocated null-terminated smb_target string. All subsequent allocations (lines 939, 964) and memcpy operations (lines 944, 946, 974) are sized using strlen() of kernel-derived strings, not directly from sub_offs or sub_len. The taint tracer incorrectly propagated taint through strlen() results. No viable counterexample exists where the callee's memory operations could overflow given the upstream bounds check and the strlen-based sizing.

Finding #1 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 145
Taint snippetsub_offs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varsub_offs
Call siteline 155 — passes sub_offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)kmalloc() line 939 (arg 0, role=size_mul_overflow)
Sink snippetlinux_target = kmalloc(symlinkroot_len + 1 + abs_path_len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: sub_offs is validated at lines 149-153 to fit within iov. In the callee, abs_path_len = strlen(abs_path)+1 is derived from a kernel-allocated string, not from sub_offs. kmalloc at line 939 is sized by strlen results. No counterexample possible.

Finding #2 — Category A — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 145
Taint snippetsub_offs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varsub_offs
Call siteline 155 — passes sub_offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)memcpy() line 944 (arg 0, role=pointer)
Sink snippetmemcpy(linux_target, symroot, symlinkroot_len);
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 944 copies symroot (a kernel config string) into linux_target sized by strlen(symroot). Neither the destination nor size depends on sub_offs. False positive from taint propagation through callee argument.

Finding #3 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 145
Taint snippetsub_offs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varsub_offs
Call siteline 155 — passes sub_offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)memcpy() line 946 (arg 2, role=size)
Sink snippetmemcpy(linux_target + symlinkroot_len + 1, abs_path, abs_path_len);
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 946 uses abs_path_len = strlen(abs_path)+1 as size, and linux_target was allocated to hold exactly symlinkroot_len+1+abs_path_len. Sizes are matched. No overflow possible.

Finding #4 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 145
Taint snippetsub_offs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varsub_offs
Call siteline 155 — passes sub_offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)kmalloc() line 964 (arg 0, role=size_mul_overflow)
Sink snippetlinux_target = kmalloc(levels*3 + smb_target_len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: kmalloc at line 964 uses levels*3 + smb_target_len where levels comes from counting separators in full_path (kernel path) and smb_target_len = strlen(smb_target)+1 from a kernel-allocated string. No direct use of sub_offs here.

Finding #5 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 145
Taint snippetsub_offs = le16_to_cpu(sym->SubstituteNameOffset);
Tainted varsub_offs
Call siteline 155 — passes sub_offs to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)memcpy() line 974 (arg 2, role=size)
Sink snippetmemcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 974 uses smb_target_len = strlen(smb_target)+1 as size, and linux_target was allocated to hold levels*3 + smb_target_len. Allocation and copy sizes match. False positive.

Finding #6 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 144
Taint snippetsub_len = le16_to_cpu(sym->SubstituteNameLength);
Tainted varsub_len
Call siteline 155 — passes sub_len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)kmalloc() line 939 (arg 0, role=size_mul_overflow)
Sink snippetlinux_target = kmalloc(symlinkroot_len + 1 + abs_path_len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: sub_len is validated at lines 149-153. In the callee, sub_len bounds the UTF-16 strndup call; abs_path_len is then strlen of the result. kmalloc at 939 is sized by strlen values. No overflow possible.

Finding #7 — Category A — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 144
Taint snippetsub_len = le16_to_cpu(sym->SubstituteNameLength);
Tainted varsub_len
Call siteline 155 — passes sub_len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)memcpy() line 944 (arg 0, role=pointer)
Sink snippetmemcpy(linux_target, symroot, symlinkroot_len);
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 944 copies symroot into linux_target; neither depends on sub_len after the UTF-16 conversion. False positive from taint tracking through callee argument.

Finding #8 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 144
Taint snippetsub_len = le16_to_cpu(sym->SubstituteNameLength);
Tainted varsub_len
Call siteline 155 — passes sub_len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)memcpy() line 946 (arg 2, role=size)
Sink snippetmemcpy(linux_target + symlinkroot_len + 1, abs_path, abs_path_len);
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 946 uses abs_path_len = strlen(abs_path)+1 which is sized from kernel string, and linux_target was allocated to match. No overflow.

Finding #9 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 144
Taint snippetsub_len = le16_to_cpu(sym->SubstituteNameLength);
Tainted varsub_len
Call siteline 155 — passes sub_len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)kmalloc() line 964 (arg 0, role=size_mul_overflow)
Sink snippetlinux_target = kmalloc(levels*3 + smb_target_len, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: kmalloc at line 964 uses levels*3 + smb_target_len from strlen of kernel strings. sub_len only influences this indirectly through the strndup-bounded UTF-16 conversion. The resulting allocation is safely sized.

Finding #10 — Category B — cross-function via smb2_parse_native_symlink() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 144
Taint snippetsub_len = le16_to_cpu(sym->SubstituteNameLength);
Tainted varsub_len
Call siteline 155 — passes sub_len to smb2_parse_native_symlink()
Call snippetreturn smb2_parse_native_symlink(path,
Sink (in callee)memcpy() line 974 (arg 2, role=size)
Sink snippetmemcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 974 copies smb_target_len bytes (from strlen) into linux_target allocated to hold exactly that. Sizes match. False positive from over-propagation of sub_len taint through strndup conversion.

check_wsl_eas() — fs/smb/client/smb2inode.c FP confidence=high

check_wsl_eas() IS the validation function. It performs careful bounds checks: (1) outlen range check at lines 117-119; (2) ea_end <= iov_end at lines 125-126; (3) sizeof(*ea) fits before ea_end at line 129 (protecting all struct field reads); (4) nlen is pinned to the compile-time constant SMB2_WSL_XATTR_NAME_LEN at line 134 before any strncmp call; (5) ea->ea_data + nlen + 1 + vlen <= ea_end at line 135. All tainted accesses occur after sufficient guards. The scanner flagged the validation logic itself as vulnerable. | check_wsl_eas() is a well-structured validator with tight per-iteration bounds checks. The loop guard at line 129 verifies sizeof(*ea) bytes are available before any field access in that iteration, including next_entry_offset at line 160. The initial outlen range check, ea_end vs iov_end check, and per-iteration guard collectively ensure all struct field accesses are within the received packet buffer. The scanner flagged the offset arithmetic used to initialize ea, but missed that the subsequent per-iteration sizeof(*ea) guard covers all fields including the flagged one.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 132
Taint snippetnlen = ea->ea_name_length;
Tainted varnlen
Truncationline 132: 16 → 8-bit u8
Sink snippetnlen = ea->ea_name_length;
Possibly guardedyes (heuristic)
Dismissed: ea_name_length is a __u8 field in smb2_file_full_ea_info, not a 16-bit field. No truncation occurs. The taint propagation from le16_to_cpu() is through the ea pointer derivation, not through the field type. Additionally, nlen is validated to equal SMB2_WSL_XATTR_NAME_LEN at line 134 before any use. False positive.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_name_length line 132
Sink snippetnlen = ea->ea_name_length;
Possibly guardedyes (heuristic)
Dismissed: Line 129 checks (u8*)ea > ea_end - sizeof(*ea) before any field access, ensuring the full struct fits within the validated buffer region. Cannot construct counterexample: if ea + sizeof(*ea) > ea_end the function returns -EINVAL before the read.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_value_length line 133
Sink snippetvlen = le16_to_cpu(ea->ea_value_length);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #2 — sizeof(*ea) check at line 129 covers ea_value_length field. False positive.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_data line 135
Sink snippet(u8 *)ea->ea_data + nlen + 1 + vlen > ea_end)
Possibly guardedyes (heuristic)
Dismissed: ea_data is a flexible array member at the end of the struct; the sizeof(*ea) check at line 129 ensures at least the fixed part fits. The access at line 135 is itself a bounds check computing whether ea_data + nlen + 1 + vlen exceeds ea_end. This is validation logic, not a vulnerable sink.

Finding #5 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varnlen
Sinkstrncmp() line 140 (arg 2, role=size)
Sink snippetif (strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) &&
Possibly guardedyes (heuristic)
Dismissed: nlen is checked at line 134: if nlen != SMB2_WSL_XATTR_NAME_LEN return -EINVAL. So at line 140, nlen equals the compile-time constant SMB2_WSL_XATTR_NAME_LEN. No counterexample possible — nlen is pinned to a constant value before strncmp.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_data line 140
Sink snippetif (strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) &&
Possibly guardedyes (heuristic)
Dismissed: sizeof(*ea) validated at line 129; ea_data bounds validated at line 135 before strncmp calls at line 140. False positive.

Finding #7 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varnlen
Sinkstrncmp() line 141 (arg 2, role=size)
Sink snippetstrncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) &&
Possibly guardedyes (heuristic)
Dismissed: Same as finding #5 — nlen pinned to SMB2_WSL_XATTR_NAME_LEN by line 134 check. False positive.

Finding #8 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_data line 141
Sink snippetstrncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) &&
Possibly guardedyes (heuristic)
Dismissed: Same as finding #6 — sizeof and data bounds validated before access. False positive.

Finding #9 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varnlen
Sinkstrncmp() line 142 (arg 2, role=size)
Sink snippetstrncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen))
Possibly guardedyes (heuristic)
Dismissed: nlen pinned to compile-time constant by line 134. False positive.

Finding #10 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_data line 142
Sink snippetstrncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen))
Possibly guardedyes (heuristic)
Dismissed: Bounds validated before access. False positive.

Finding #11 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varnlen
Sinkstrncmp() line 146 (arg 2, role=size)
Sink snippetif (strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
Possibly guardedyes (heuristic)
Dismissed: nlen pinned to compile-time constant by line 134. False positive.

Finding #12 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_data line 146
Sink snippetif (strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
Possibly guardedyes (heuristic)
Dismissed: Bounds validated before access. False positive.

Finding #13 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varnlen
Sinkstrncmp() line 150 (arg 2, role=size)
Sink snippetif (!strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) ||
Possibly guardedyes (heuristic)
Dismissed: nlen pinned to compile-time constant by line 134. False positive.

Finding #14 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_data line 150
Sink snippetif (!strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) ||
Possibly guardedyes (heuristic)
Dismissed: Bounds validated before access. False positive.

Finding #15 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varnlen
Sinkstrncmp() line 151 (arg 2, role=size)
Sink snippet!strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) ||
Possibly guardedyes (heuristic)
Dismissed: nlen pinned to compile-time constant by line 134. False positive.

Finding #16 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_data line 151
Sink snippet!strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) ||
Possibly guardedyes (heuristic)
Dismissed: Bounds validated before access. False positive.

Finding #17 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varnlen
Sinkstrncmp() line 152 (arg 2, role=size)
Sink snippet!strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen) ||
Possibly guardedyes (heuristic)
Dismissed: nlen pinned to compile-time constant by line 134. False positive.

Finding #18 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_data line 152
Sink snippet!strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen) ||
Possibly guardedyes (heuristic)
Dismissed: Bounds validated before access. False positive.

Finding #19 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varnlen
Sinkstrncmp() line 153 (arg 2, role=size)
Sink snippet!strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
Possibly guardedyes (heuristic)
Dismissed: nlen pinned to compile-time constant by line 134. False positive.

Finding #20 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->ea_data line 153
Sink snippet!strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
Possibly guardedyes (heuristic)
Dismissed: Bounds validated before access. False positive.

Finding #21 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 121
Taint snippetea = (void *)((u8 *)rsp_iov->iov_base +
Tainted varea
Pointer derefea->next_entry_offset line 160
Sink snippetnext = le32_to_cpu(ea->next_entry_offset);
Possibly guardedyes (heuristic)
Dismissed: Line 129 checks `(u8 *)ea > ea_end - sizeof(*ea)`, i.e. ensures at least sizeof(*ea) bytes remain before ea_end on every loop iteration. Since next_entry_offset is a field within struct smb2_file_full_ea_info, this guard fully covers the dereference at line 160. No counterexample can pass line 129 while causing OOB at line 160 — the guard is structurally tight. False positive.

parse_posix_sids() — fs/smb/client/smb2inode.c FP confidence=high

The function has a complete validation chain. Before parse_posix_sids() is called, smb2_validate_and_copy_iov() verifies OutputBufferOffset and OutputBufferLength against the actual iov buffer size. Inside parse_posix_sids(), posix_info_sid_size() validates: (1) the SID fits within [sidsbuf, sidsbuf_end], (2) the subauth count is in [1,15], making the maximum return value 68 bytes (1+1+6+4*15). The destination structs (posix_owner, posix_group of type cifs_sid) are sized to accommodate a maximum SID. No counterexample can be constructed that passes all guards yet causes OOB access.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 75
Taint snippetsidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
Tainted varowner_len
Sinkmemcpy() line 82 (arg 2, role=size)
Sink snippetmemcpy(&data->posix_owner, sidsbuf, owner_len);
Possibly guardedyes (heuristic)
Dismissed: owner_len is the return value of posix_info_sid_size(), which (a) validates that sidsbuf+owner_len <= sidsbuf_end (no OOB read of source), and (b) caps owner_len at max 68 (subauth in [1,15]). The destination data->posix_owner is struct cifs_sid which is sized to hold a maximum SID of 68 bytes. Cannot construct a counterexample.

Finding #2 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 75
Taint snippetsidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
Tainted varsidsbuf
Sinkmemcpy() line 82 (arg 1, role=pointer)
Sink snippetmemcpy(&data->posix_owner, sidsbuf, owner_len);
Possibly guardedno
Dismissed: sidsbuf is derived from server-supplied OutputBufferOffset, but smb2_validate_and_copy_iov() (called before parse_posix_sids) validates OutputBufferOffset+length fits within the iov. Additionally, posix_info_sid_size() checks beg+total <= end before returning, confirming sidsbuf and its contents are within bounds.

Finding #3 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 75
Taint snippetsidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
Tainted vargroup_len
Sinkmemcpy() line 87 (arg 2, role=size)
Sink snippetmemcpy(&data->posix_group, sidsbuf + owner_len, group_len);
Possibly guardedyes (heuristic)
Dismissed: group_len is returned by posix_info_sid_size(sidsbuf+owner_len, sidsbuf_end), which validates the group SID fits within [sidsbuf+owner_len, sidsbuf_end]. group_len is bounded to max 68 bytes by the subauth in [1,15] check. Cannot construct a counterexample.

Finding #4 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 75
Taint snippetsidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
Tainted varsidsbuf
Sinkmemcpy() line 87 (arg 1, role=pointer)
Sink snippetmemcpy(&data->posix_group, sidsbuf + owner_len, group_len);
Possibly guardedno
Dismissed: sidsbuf+owner_len is the base pointer passed to posix_info_sid_size() for the group SID, which verifies beg+2 <= end before reading, and beg+total <= end before returning. The pointer arithmetic is validated by posix_info_sid_size() before memcpy uses it.

reparse_buf_ptr() — fs/smb/client/smb2inode.c BUG confidence=high

The function validates off+count fits in the IOV buffer, then dereferences buf->ReparseDataLength before checking that count >= sizeof(*buf). The structural size check (count < len) happens after the dereference on line 43, not before it, allowing a server to supply a small OutputCount value that passes the overflow check but causes an OOB read when the struct fields are accessed.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 36
Taint snippetoff = le32_to_cpu(io->OutputOffset);
Tainted varbuf
Pointer derefbuf->ReparseDataLength line 43
Sink snippetrdlen = le16_to_cpu(buf->ReparseDataLength);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in reparse_buf_ptr reading buf->ReparseDataLength; kernel crash or information disclosure if a server returns OutputOffset near the end of the buffer with OutputCount < sizeof(struct reparse_data_buffer)
Fix: Move the 'count < sizeof(*buf)' check to before the struct dereference: after computing buf on line 41, immediately check 'if (count < sizeof(*buf)) return ERR_PTR(-EIO);' before accessing buf->ReparseDataLength on line 43. The current check at line 45 needs to precede line 43.
CVE pattern: DataOffset OOB read — server-controlled offset and length allow struct field access beyond validated buffer region

smb2_compound_op() — fs/smb/client/smb2inode.c FP confidence=high

The flagged call to smb2_validate_and_copy_iov() is itself the validation function. The callee source clearly shows that smb2_validate_and_copy_iov() calls smb2_validate_iov() on the offset and buffer_length before computing begin_of_buf and performing the memcpy. The memcpy at line 3868 is only reached after smb2_validate_iov() returns 0, meaning the offset+buffer_length combination has already been validated to fit within the iov buffer. This is a validator-internal access pattern (false positive category 2/4 in the guidelines): the flagged sink IS the validation logic, not a vulnerable sink.

Finding #1 — Category A — cross-function via smb2_validate_and_copy_iov() — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 608
Taint snippetrc = smb2_validate_and_copy_iov(
Tainted varle16_to_cpu(qi_rsp->OutputBufferOffset)
Call siteline 608 — passes le16_to_cpu(qi_rsp->OutputBufferOffset) to smb2_validate_and_copy_iov()
Call snippetrc = smb2_validate_and_copy_iov(
Sink (in callee)memcpy() line 3868 (arg 1, role=pointer)
Sink snippetmemcpy(data, begin_of_buf, minbufsize);
Possibly guardedno
Dismissed: qi_rsp is a server response buffer, so OutputBufferOffset is genuinely server-supplied and tainted. However, smb2_validate_and_copy_iov() is explicitly a validation-and-copy helper: it calls smb2_validate_iov(offset, buffer_length, iov, minbufsize) before computing begin_of_buf = offset + (char *)iov->iov_base and calling memcpy(). If smb2_validate_iov() succeeds, it has confirmed that offset + buffer_length fits within iov->iov_len and that buffer_length >= minbufsize. Therefore begin_of_buf is within the iov buffer and the memcpy of minbufsize bytes is safe. No counterexample can be constructed: any offset value that would cause OOB access would be rejected by smb2_validate_iov(). The scanner flagged the memcpy inside the callee as a sink without recognizing that the callee is a purpose-built validator that guards that very memcpy.

__smb2_calc_size() — fs/smb/client/smb2misc.c VALIDATE confidence=medium

The primary call site smb2_check_message() likely validates shdr->Command in the 19 omitted lines (since it also uses 'command' as array subscript at line 218 with smb2_rsp_struct_sizes). However, the secondary call site smb2_calc_size() performs no validation before calling __smb2_calc_size(), leaving a potential OOB array read if Command is out of range. The finding is plausible for the smb2_calc_size() path but likely a false positive for the smb2_check_message() path.

Finding #1 — Category C — BUG oob_read

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 454
Taint snippetif (has_smb2_data_area[le16_to_cpu(shdr->Command)] == false)
Tainted varle16_to_cpu(shdr->Command)
Subscript[] line 454
Sink snippetif (has_smb2_data_area[le16_to_cpu(shdr->Command)] == false)
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: global-out-of-bounds in __smb2_calc_size when server sends malformed Command value; potential info disclosure or kernel panic
Fix: Before indexing has_smb2_data_area[], validate that le16_to_cpu(shdr->Command) is less than the array size (e.g., SMB2_NUM_CMDS or ARRAY_SIZE(has_smb2_data_area)). Add: 'if (command >= ARRAY_SIZE(has_smb2_data_area)) goto calc_size_exit;' or validate command in smb2_calc_size() before calling __smb2_calc_size().
CVE pattern: Out-of-bounds array read via unvalidated server-supplied command field in SMB2 message parsing

smb2_check_message() — fs/smb/client/smb2misc.c FP confidence=high

The function smb2_check_message() is a validation function for server responses. The 'command' value is indeed server-supplied (read from a received network buffer via le16_to_cpu(shdr->Command)). However, the bounds check at lines 193-196 explicitly validates 'command' against NUMBER_OF_SMB2_COMMANDS before the array subscript at line 218. The check 'if (command >= NUMBER_OF_SMB2_COMMANDS)' with an early return of 1 is a proper and sufficient bounds guard. The array smb2_rsp_struct_sizes is indexed by command values 0..NUMBER_OF_SMB2_COMMANDS-1, and any out-of-range value causes an early return before the subscript.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 192
Taint snippetcommand = le16_to_cpu(shdr->Command);
Tainted varcommand
Subscript[] line 218
Sink snippetif (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
Possibly guardedyes (heuristic)
Dismissed: The guard at lines 193-196 checks 'if (command >= NUMBER_OF_SMB2_COMMANDS) { return 1; }' which is a tight upper-bound check. After this check, command is in [0, NUMBER_OF_SMB2_COMMANDS-1], which is exactly the valid index range for smb2_rsp_struct_sizes[]. No counterexample can be constructed: any value of command that would index out-of-bounds (>= NUMBER_OF_SMB2_COMMANDS) is rejected before reaching line 218. The scanner's 'possibly guarded' flag correctly detected the conditional but did not confirm its sufficiency — in this case it is fully sufficient.

smb2_tcon_find_pending_open_lease() — fs/smb/client/smb2misc.c VALIDATE confidence=medium

The rsp pointer is a cast from a network buffer (server response), so rsp->NewLeaseState is genuinely server-supplied. The value is a 32-bit lease state field that is silently truncated to __u8 when stored in 'lease_state'. The lease_state value is later assigned to open->oplock. The question is whether valid SMB2 lease states fit within 8 bits. SMB2 lease states are defined as: SMB2_LEASE_NONE=0x00, SMB2_LEASE_READ=0x01, SMB2_LEASE_HANDLE=0x02, SMB2_LEASE_WRITE=0x04, and combinations thereof (max 0x07). So in practice, a compliant server would only ever set values 0-7. However, a malicious server could set high bits (e.g., 0x100) that would be silently dropped, causing the oplock to appear as a different (lower) state than intended. This could lead to incorrect oplock/lease state tracking, but not memory corruption.

Finding #1 — Category H — BUG integer_overflow

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele32_to_cpu() line 612
Taint snippet__u8 lease_state = le32_to_cpu(rsp->NewLeaseState);
Tainted varlease_state
Truncationline 612: 32 → 8-bit __u8
Sink snippet__u8 lease_state = le32_to_cpu(rsp->NewLeaseState);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: Incorrect lease/oplock state stored in open->oplock; a malicious server sending NewLeaseState=0x100 would result in oplock=0x00 (NONE) instead of a non-zero value, potentially causing the client to believe it has no lease when it does or vice versa, leading to cache coherency bugs or missed lease break acknowledgements.
Fix: Validate that rsp->NewLeaseState contains only known lease state bits before truncating: u32 raw_state = le32_to_cpu(rsp->NewLeaseState); if (raw_state & ~(SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE)) { /* log and reject or mask */ } __u8 lease_state = raw_state & 0x07; Alternatively, change the type of open->oplock and lease_state to u32 to avoid truncation.

smb2_tcon_has_lease() — fs/smb/client/smb2misc.c BUG confidence=medium

The function reads rsp->NewLeaseState from a server-supplied network buffer via le32_to_cpu(), producing a 32-bit value, then silently truncates it to an 8-bit __u8. The SMB2 lease state field is a 32-bit bitmask (e.g., SMB2_LEASE_READ_CACHING=0x01, WRITE=0x02, HANDLE=0x04), so legitimate values fit in 8 bits in practice — but a malicious server could supply a value with bits set above bit 7, which would be silently dropped. The truncated value is later stored in cfile->oplock_level and used in oplock break processing logic. No masking or explicit bounds check is applied before the assignment.

Finding #1 — Category H — BUG integer_overflow

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele32_to_cpu() line 578
Taint snippetlease_state = le32_to_cpu(rsp->NewLeaseState);
Tainted varlease_state
Truncationline 578: 32 → 8-bit u8
Sink snippetlease_state = le32_to_cpu(rsp->NewLeaseState);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: A malicious server could send a lease break with NewLeaseState having bits set above bit 7; the upper bits would be silently truncated, causing the kernel to record an incorrect lease/oplock level in cfile->oplock_level. This could lead to incorrect caching decisions or failure to properly invalidate page cache, potentially resulting in data corruption or security policy bypass rather than a crash.
Fix: Either declare lease_state as __le32/__u32 (matching the protocol field width) and update all consumers to handle 32-bit values, or explicitly mask the value before truncation: lease_state = le32_to_cpu(rsp->NewLeaseState) & 0xFF; and add a check that the high bits are zero (returning false or logging a warning if a server sends an unexpected value). The cleanest fix is to widen cfile->oplock_level to u32 or validate that NewLeaseState only contains known bits (SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING | SMB2_LEASE_HANDLE_CACHING).
CVE pattern: Silent integer truncation of server-supplied field before use in state machine logic

crypt_message() — fs/smb/client/smb2ops.c FP confidence=high

The scanner misidentified the taint flow. le64_to_cpu(tr_hdr->SessionId) at line 4627 is passed as a u64 argument to smb2_get_enc_key(), and the RETURN VALUE of smb2_get_enc_key() is stored in 'rc' (an int). The 64-bit value is not truncated into 'rc'; 'rc' receives the integer error code returned by the function call. The le64_to_cpu() result is passed by value to the function and is never assigned to 'rc'. This is a classic taint-tracking false positive where the scanner incorrectly propagated taint from a function argument through the function's return value.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele64_to_cpu() line 4627
Taint snippetrc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key);
Tainted varrc
Truncationline 4627: 64 → 32-bit u32
Sink snippetrc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key);
Possibly guardedno
Dismissed: The scanner claims le64_to_cpu(tr_hdr->SessionId) is truncated into 'rc' (32-bit), but this is incorrect. The expression 'rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key)' stores the RETURN VALUE of smb2_get_enc_key() into 'rc', not the 64-bit SessionId argument. The SessionId (u64) is passed by value as the second argument to smb2_get_enc_key() and is not truncated — it is used as a lookup key inside that function. 'rc' receives an int error code from the callee. No truncation of a 64-bit server-supplied value into 'rc' occurs. This is a false positive due to overly conservative taint propagation through function call arguments.

move_smb2_ea_to_cifs() — fs/smb/client/smb2ops.c FP confidence=high

The function move_smb2_ea_to_cifs() has solid validation discipline. For finding #1, value_len is bounded by the src_size check at line 1064 (source buffer) and by explicit dst_size checks before memcpy (destination buffer). For finding #2, the new src pointer is only dereferenced to read next_entry_offset at line 1113 in the NEXT iteration, and before that dereference the loop checks src_size > 0, plus the src_size >= next_entry_offset check at line 1113 ensures at least that many bytes remain. Since smb2_file_full_ea_info is small and the remaining src_size is validated against next_entry_offset before the advance, the new pointer is within bounds.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1059
Taint snippetvalue_len = (size_t)le16_to_cpu(src->ea_value_length);
Tainted varvalue_len
Sinkmemcpy() line 1084 (arg 2, role=size)
Sink snippetmemcpy(dst, value, value_len);
Possibly guardedyes (heuristic)
Dismissed: For source buffer: line 1064 checks src_size < 8 + name_len + 1 + value_len, ensuring value_len bytes are present in the source after the header and name. For destination buffer: line 1080 checks dst_size < value_len and returns -ERANGE if true; only if dst_size >= value_len does execution reach memcpy(dst, value, value_len) at line 1084. No counterexample can be constructed — any value_len that passes both guards is safe for both source and destination.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1119
Taint snippetsrc = (void *)((char *)src +
Tainted varsrc
Pointer derefsrc->next_entry_offset line 1120
Sink snippetle32_to_cpu(src->next_entry_offset));
Possibly guardedno
Dismissed: The pointer advance at lines 1119-1120 is preceded by two guards: (1) line 1110 breaks if next_entry_offset is 0, avoiding infinite loops; (2) line 1113 checks src_size < le32_to_cpu(src->next_entry_offset) and breaks with -ERANGE if true. After the advance, src_size is decremented by next_entry_offset at line 1118. The new src pointer thus points within the original buffer (the advance is <= src_size bytes from the current position). On the next iteration, src_size > 0 is checked and any subsequent struct field read is within the validated remaining buffer. The deref of src->next_entry_offset at line 1120 (the le32_to_cpu call completing the assignment) is at the same address as line 1113's read, so it is within bounds by the guard already evaluated.

parse_server_interfaces() — fs/smb/client/smb2ops.c FP confidence=high

parse_server_interfaces() has reasonable validation discipline: it checks `next > bytes_left` before advancing `p`, and uses short-circuit evaluation to guard the post-loop `p->Next` access with a bytes_left size check. The scanner flagged the post-loop p->Next access at line 807, but the `&&` short-circuit on line 806 (bytes_left >= offsetof(Next)+sizeof(p->Next)) ensures the access is within the remaining buffer before dereferencing p->Next.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 782
Taint snippetnext = le32_to_cpu(p->Next);
Tainted varp
Pointer derefp->Next line 807
Sink snippet+ sizeof(p->Next) && p->Next))
Possibly guardedno
Dismissed: The access `p->Next` at line 807 is protected by the short-circuit `&&` condition on line 806: `bytes_left >= offsetof(struct network_interface_info_ioctl_rsp, Next) + sizeof(p->Next)` must evaluate to true before `p->Next` is read. Since `bytes_left` is decremented by validated `next` values (each checked against `bytes_left` at line 788), `p + bytes_left` always stays within the original buffer. No counterexample can be constructed: any `bytes_left` small enough to allow OOB would fail the offsetof check and short-circuit the &&, preventing the dereference.

receive_encrypted_standard() — fs/smb/client/smb2ops.c BUG confidence=medium

The function reads next_cmd from a decrypted server response and uses it in a memcpy. While there is a guard preventing next_cmd > pdu_length (preventing source OOB read and size underflow), there is no check ensuring the destination buffer (cifs_buf_get or cifs_small_buf_get, whose sizes are fixed pool allocations) is large enough to hold pdu_length - next_cmd bytes. The next_is_large flag controlling buffer type selection is not re-evaluated against the actual remaining data size.

Finding #1 — Category B — BUG oob_write

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 5252
Taint snippetnext_cmd = le32_to_cpu(shdr->NextCommand);
Tainted varnext_cmd
Sinkmemcpy() line 5270 (arg 2, role=size)
Sink snippetmemcpy(next_buffer, buf + next_cmd, pdu_length - next_cmd);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in receive_encrypted_standard when copying compound PDU remainder into undersized buffer; heap corruption potentially leading to kernel panic or privilege escalation
Fix: Before selecting next_buffer type (large vs small), compute the remaining data size (pdu_length - next_cmd) and ensure next_is_large is set to true if that size exceeds MAX_CIFS_SMALL_BUFFER_SIZE. Add a bounds check: if (pdu_length - next_cmd > (next_is_large ? CIFSMaxBufSize + MAX_HEADER_SIZE(server) : MAX_CIFS_SMALL_BUFFER_SIZE)) return -1; Additionally verify next_cmd is at a valid aligned offset (e.g., >= sizeof(struct smb2_hdr)) before using it.
CVE pattern: SMB compound response heap overflow via malformed NextCommand offset

smb2_query_eas() — fs/smb/client/smb2ops.c FP confidence=high

smb2_query_eas() calls smb2_validate_iov() before using any server-supplied offsets or lengths, establishing that the info pointer and OutputBufferLength are within the received buffer. move_smb2_ea_to_cifs() then performs per-entry bounds checking at line 1064 (src_size < 8 + name_len + 1 + value_len) before any subscript or memcpy operations, and checks dst_size before writing. All flagged sinks are protected by this two-level validation chain.

Finding #1 — Category C — cross-function via move_smb2_ea_to_cifs() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 1170
Taint snippetinfo = (struct smb2_file_full_ea_info *)(
Tainted varinfo
Call siteline 1172 — passes info to move_smb2_ea_to_cifs()
Call snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Subscript (in callee)[] line 1072
Sink snippetvalue = &src->ea_data[src->ea_name_length + 1];
Possibly guardedno
Dismissed: smb2_validate_iov() validates the offset and OutputBufferLength fit in the iov buffer before info is computed. In move_smb2_ea_to_cifs(), the check at line 1064 ensures src_size >= 8 + name_len + 1 + value_len before accessing ea_data[name_len+1]. No counterexample: any name_len or value_len that would push the subscript out of bounds would fail the line 1064 check first. False positive.

Finding #2 — Category B — cross-function via move_smb2_ea_to_cifs() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1170
Taint snippetinfo = (struct smb2_file_full_ea_info *)(
Tainted varinfo
Call siteline 1172 — passes info to move_smb2_ea_to_cifs()
Call snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Sink (in callee)memcmp() line 1076 (arg 2, role=size)
Sink snippetmemcmp(ea_name, name, name_len) == 0) {
Possibly guardedyes (heuristic)
Dismissed: name_len is derived from src->ea_name_length (1-byte field, max 255). The check at line 1064 ensures name_len fits within src_size before memcmp is called. Additionally, ea_name_len is from strlen(ea_name) which is caller-controlled (not server-supplied). The memcmp size is min(ea_name_len, name_len) effectively via the ea_name_len == name_len equality check first. False positive.

Finding #3 — Category B — cross-function via move_smb2_ea_to_cifs() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1170
Taint snippetinfo = (struct smb2_file_full_ea_info *)(
Tainted varinfo
Call siteline 1172 — passes info to move_smb2_ea_to_cifs()
Call snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Sink (in callee)memcpy() line 1084 (arg 2, role=size)
Sink snippetmemcpy(dst, value, value_len);
Possibly guardedyes (heuristic)
Dismissed: value_len is le16_to_cpu(src->ea_value_length), max 65535. Line 1064 checks src_size >= 8 + name_len + 1 + value_len, bounding value_len within the validated buffer. Line 1080 checks dst_size >= value_len before memcpy. Cannot construct counterexample: both buffer-side and destination-side checks are in place. False positive.

Finding #4 — Category B — cross-function via move_smb2_ea_to_cifs() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1170
Taint snippetinfo = (struct smb2_file_full_ea_info *)(
Tainted varinfo
Call siteline 1172 — passes info to move_smb2_ea_to_cifs()
Call snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Sink (in callee)memcpy() line 1098 (arg 2, role=size)
Sink snippetmemcpy(dst, src->ea_data, name_len);
Possibly guardedyes (heuristic)
Dismissed: name_len (1-byte field) is checked at line 1064 to be within src_size. Line 1094 checks dst_size >= user_name_len (which includes name_len) before memcpy at line 1098. Both source and destination bounds are validated. False positive.

Finding #5 — Category E — cross-function via move_smb2_ea_to_cifs() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1170
Taint snippetinfo = (struct smb2_file_full_ea_info *)(
Tainted varinfo
Call siteline 1172 — passes info to move_smb2_ea_to_cifs()
Call snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Pointer derefinfo-> line 1120
Sink snippetle32_to_cpu(src->next_entry_offset));
Possibly guardedno
Dismissed: Line 1120 accesses src->next_entry_offset for loop advancement. The src pointer at this point is within the validated iov buffer (smb2_validate_iov ensures OutputBufferLength fits). The struct field access itself (reading next_entry_offset from within the validated buffer) is safe as long as src points within the buffer. The callee code (not fully shown) likely validates next_entry_offset before advancing src, following the same pattern as smb2_parse_lease_buf and similar SMB2 parsers. The taint tracker conflates pointer-derivation taint with actual vulnerability. False positive.

Finding #6 — Category F — cross-function via move_smb2_ea_to_cifs() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 1172
Taint snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Tainted varle32_to_cpu(rsp->OutputBufferLength)
Call siteline 1172 — passes le32_to_cpu(rsp->OutputBufferLength) to move_smb2_ea_to_cifs()
Call snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Loopwhile_loop line 1057
Sink snippetwhile (src_size > 0) {
Possibly guardedno
Dismissed: OutputBufferLength controls the while loop bound as src_size. However, smb2_validate_iov() at line 1163 validates that OutputBufferOffset + OutputBufferLength fits within the iov buffer, so src_size is bounded by the actual received data size. The loop subtracts from src_size each iteration (via next_entry_offset advancement), and the per-entry check at line 1064 ensures each entry fits within remaining src_size. The loop is bounded by actual buffer content. False positive.

Finding #7 — Category B — cross-function via move_smb2_ea_to_cifs() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 1172
Taint snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Tainted varle32_to_cpu(rsp->OutputBufferLength)
Call siteline 1172 — passes le32_to_cpu(rsp->OutputBufferLength) to move_smb2_ea_to_cifs()
Call snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Sink (in callee)memcpy() line 1084 (arg 2, role=size)
Sink snippetmemcpy(dst, value, value_len);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #3 — value_len is doubly bounded: by the src_size check at line 1064 and by dst_size check at line 1080. The src_size itself is validated by smb2_validate_iov(). False positive.

Finding #8 — Category E — cross-function via move_smb2_ea_to_cifs() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 1172
Taint snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Tainted varle32_to_cpu(rsp->OutputBufferLength)
Call siteline 1172 — passes le32_to_cpu(rsp->OutputBufferLength) to move_smb2_ea_to_cifs()
Call snippetrc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
Pointer derefle32_to_cpu(rsp->OutputBufferLength)-> line 1120
Sink snippetle32_to_cpu(src->next_entry_offset));
Possibly guardedno
Dismissed: Same as finding #5 — the src pointer is within the validated iov buffer (OutputBufferLength validated by smb2_validate_iov). The struct field access src->next_entry_offset reads from within the validated region. The taint on OutputBufferLength does not create a vulnerability at the point of reading next_entry_offset from the validated buffer. False positive.

smb3_enum_snapshots() — fs/smb/client/smb2ops.c FP confidence=high

ret_data_len is bounded by two guards before copy_to_user: (1) the actual server response length from SMB2_ioctl (bounded by max_response_size = size of retbuf allocation), and (2) a cap to snapshot_in.snapshot_array_size + sizeof(struct smb_snapshot_array), which is derived from the user's own declared buffer size. No counterexample can be constructed where ret_data_len exceeds either retbuf or the user-declared buffer.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 2390
Taint snippetif (copy_to_user(ioc_buf, retbuf, ret_data_len))
Tainted varret_data_len
Unvalidated sizecopy_to_user() arg 2 line 2390 — size ret_data_len
Sink snippetif (copy_to_user(ioc_buf, retbuf, ret_data_len))
Possibly guardedno
Dismissed: ret_data_len after SMB2_ioctl() reflects actual received bytes, capped by max_response_size (the allocation size of retbuf). Before copy_to_user, it is further capped to snapshot_in.snapshot_array_size + sizeof(struct smb_snapshot_array), which is what the user declared as their buffer capacity. No counterexample found: the guards are sufficient on both the source buffer (retbuf) and destination buffer (ioc_buf) sides.

smb3_fiemap() — fs/smb/client/smb2ops.c FP confidence=high

The function has reasonable validation of out_data_len before array access. The flagged finding is a scanner error: rc receives the int return value of fiemap_fill_next_extent(), not a truncated le64_to_cpu() value. The le64_to_cpu() results are passed as u64 arguments to fiemap_fill_next_extent(), which accepts u64 parameters — no truncation occurs. A separate potential issue exists if num==0 and last_blob==0 (OOB at out_data[num-1]), but that is not what the scanner flagged.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele64_to_cpu() line 4170
Taint snippetrc = fiemap_fill_next_extent(fei,
Tainted varrc
Truncationline 4170: 64 → 32-bit u32
Sink snippetrc = fiemap_fill_next_extent(fei,
Possibly guardedno
Dismissed: The scanner incorrectly identifies rc as receiving a truncated 64-bit server-supplied value. In reality, rc is assigned the int return value of fiemap_fill_next_extent(). The le64_to_cpu() expressions produce u64 arguments passed to that function's u64 parameters — no truncation of server data into rc occurs. This is a scanner false positive from misattributing taint from the arguments to the return value of the same call expression.

smb3_simple_fallocate_range() — fs/smb/client/smb2ops.c FP confidence=high

The function has reasonable validation discipline: out_data_len is checked against sizeof(struct file_allocated_range_buffer) before accessing tmp_data fields, and range_start+range_len overflow is checked with check_add_overflow before use. The scanner's finding is based on a misidentification of the taint flow.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele64_to_cpu() line 3685
Taint snippetrc = smb3_simple_fallocate_write_range(xid, tcon,
Tainted varrc
Truncationline 3685: 64 → 32-bit u32
Sink snippetrc = smb3_simple_fallocate_write_range(xid, tcon,
Possibly guardedno
Dismissed: The scanner claims a 64-bit server value is truncated into 32-bit 'rc' at line 3685. However, 'rc' is assigned the return value of smb3_simple_fallocate_write_range(), which returns int — not a server-supplied 64-bit value. The server-supplied variable 'l' (loff_t, derived from range_start) is passed as an argument to that function, not assigned to rc. The taint propagation model is incorrect here. Furthermore, range_start and range_len from the server are protected by check_add_overflow() and the range_end > S64_MAX check before any use, and out_data_len is validated against sizeof(struct file_allocated_range_buffer) before tmp_data is dereferenced. No counterexample can be constructed because no truncation of server data into rc actually occurs.

SMB2_QFS_attr() — fs/smb/client/smb2pdu.c FP confidence=high

smb2_validate_iov() is called at line 6267 before any data access. It validates: (1) rsp_len >= min_len, (2) both values <= 0x7FFFFF, (3) [offset+iov_base, offset+iov_base+rsp_len] lies within the iov buffer. This establishes safety for all subsequent struct pointer dereferences and memcpy operations, since min_len equals sizeof() of each target struct for sector/volume levels, and the FS_ATTRIBUTE case uses min_t(unsigned int, rsp_len, min_len) to cap the destination write to sizeof(FILE_SYSTEM_ATTRIBUTE_INFO).

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 6265
Taint snippetrsp_len = le32_to_cpu(rsp->OutputBufferLength);
Tainted varrsp_len
Sinkmemcpy() line 6272 (arg 2, role=size)
Sink snippetmemcpy(&tcon->fsAttrInfo, offset
Possibly guardedno
Dismissed: smb2_validate_iov ensures rsp_len fits within the source iov (no OOB read). The destination is bounded by min_t(unsigned int, rsp_len, min_len) where min_len=sizeof(FILE_SYSTEM_ATTRIBUTE_INFO), so no OOB write. Cannot construct a counterexample: rsp_len passing smb2_validate_iov is <= iov_len-offset, and min_t caps destination write to min_len=struct size.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6266
Taint snippetoffset = le16_to_cpu(rsp->OutputBufferOffset);
Tainted varss_info
Pointer derefss_info->Flags line 6281
Sink snippettcon->ss_flags = le32_to_cpu(ss_info->Flags);
Possibly guardedno
Dismissed: smb2_validate_iov called with min_len=sizeof(struct smb3_fs_ss_info) ensures rsp_len>=sizeof(*ss_info) and offset+rsp_len fits in iov. Thus offset+sizeof(*ss_info)<=packet_end. The ss_info->Flags dereference is safe. No counterexample possible.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6266
Taint snippetoffset = le16_to_cpu(rsp->OutputBufferOffset);
Tainted varss_info
Pointer derefss_info->PhysicalBytesPerSectorForPerf line 6283
Sink snippetle32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf);
Possibly guardedno
Dismissed: Same guard as finding #2 protects ss_info->PhysicalBytesPerSectorForPerf. smb2_validate_iov guarantees the full struct fits in the packet buffer.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6266
Taint snippetoffset = le16_to_cpu(rsp->OutputBufferOffset);
Tainted varvol_info
Pointer derefvol_info->VolumeSerialNumber line 6287
Sink snippettcon->vol_serial_number = le32_to_cpu(vol_info->VolumeSerialNumber);
Possibly guardedno
Dismissed: smb2_validate_iov called with min_len=sizeof(struct filesystem_vol_info) ensures rsp_len>=sizeof(*vol_info) and the region [offset, offset+rsp_len] fits in iov. vol_info->VolumeSerialNumber dereference is safe. No counterexample possible.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6266
Taint snippetoffset = le16_to_cpu(rsp->OutputBufferOffset);
Tainted varvol_info
Pointer derefvol_info->VolumeCreationTime line 6288
Sink snippettcon->vol_create_time = vol_info->VolumeCreationTime;
Possibly guardedno
Dismissed: Same guard as finding #4 protects vol_info->VolumeCreationTime. smb2_validate_iov guarantees the full filesystem_vol_info struct fits within the validated buffer region.

__smb2_plain_req_init() — fs/smb/client/smb2pdu.c FP confidence=high

The function __smb2_plain_req_init() is a request initializer — it builds outgoing SMB2 request packets. The smb2_command parameter is always a kernel-defined constant (SMB2_NEGOTIATE, SMB2_IOCTL, SMB2_SET_INFO, etc.) passed from callers, never a value parsed from a server response buffer. The le16_to_cpu() call is purely an endian normalization of an internally-controlled value, not a deserialization of server-supplied data. Both call sites confirm this: smb2_plain_req_init propagates a constant from its own callers, and smb2_ioctl_req_init passes SMB2_IOCTL literally.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 577
Taint snippetuint16_t com_code = le16_to_cpu(smb2_command);
Tainted varcom_code
Subscript[] line 578
Sink snippetcifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]);
Possibly guardedno
Dismissed: The scanner mistakenly treats le16_to_cpu() as a server-supplied taint source, but smb2_command is a kernel-defined constant (e.g., SMB2_IOCTL=0x000B, SMB2_SET_INFO=0x0011) passed into this request-building function. No counterexample is possible because the values are compile-time constants controlled entirely by the kernel, not by any server response. This is a classic false positive from pattern 1: internally-constructed request fields round-tripped through endian conversion.

decode_compress_ctx() — fs/smb/client/smb2pdu.c FP confidence=high

The function decode_compress_ctx() performs careful multi-level validation before the loop. The count variable is bounded both by ARRAY_SIZE(ctxt->CompressionAlgorithms) (a compile-time constant limiting the array size) and by checking that len >= 8 + count * sizeof(__le16). These two checks together ensure that (1) count cannot exceed the statically-allocated array size in the struct, and (2) count * sizeof element fits within the declared DataLength. No counterexample can be constructed that passes both guards yet causes OOB access.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 853
Taint snippetcount = le16_to_cpu(ctxt->CompressionAlgorithmCount);
Tainted varcount
Loopfor_loop line 866
Sink snippetfor (i = 0; i < count; i++) {
Possibly guardedyes (heuristic)
Dismissed: At line 854-858, count is validated against two independent upper bounds: (a) count > ARRAY_SIZE(ctxt->CompressionAlgorithms) ensures the loop index i < count never exceeds the statically-declared array dimension, and (b) len < 8 + count * sizeof(__le16) ensures count * element_size fits within the DataLength field. A counterexample would require count > ARRAY_SIZE(ctxt->CompressionAlgorithms) or count * 2 > len - 8, both of which are caught by the guard that returns early. No counterexample exists — the checks are sufficient.

fill_small_buf() — fs/smb/client/smb2pdu.c FP confidence=high

The smb2_command parameter in fill_small_buf() is an internally-constructed kernel command code used when building outgoing SMB2 requests, not a value parsed from a server response buffer. The le16_to_cpu() call on this parameter triggers the taint analysis, but the value originates from kernel-internal logic in __smb2_plain_req_init() and its callers, not from network data. The array indexing into smb2_req_struct_sizes[] is therefore not a server-controlled OOB risk.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 534
Taint snippet__u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_command)];
Tainted varle16_to_cpu(smb2_command)
Subscript[] line 534
Sink snippet__u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_command)];
Possibly guardedno
Dismissed: smb2_command is a kernel-internal command code constant (e.g., SMB2_SET_INFO, SMB2_QUERY_INFO) passed from kernel request-building logic, not read from a server response. The le16_to_cpu() call on this value falsely triggers taint marking. No counterexample can be constructed because the value set is bounded by kernel-defined SMB2 command enumerations. This is a classic false positive from pattern #1: endian conversion on a locally-written field.

parse_posix_ctxt() — fs/smb/client/smb2pdu.c FP confidence=high

parse_posix_ctxt() is well-protected. The caller smb2_parse_contexts() validates that DataOffset+DataLength fits within the response iov before calling parse_posix_ctxt(), establishing safe beg/end pointers. Inside parse_posix_ctxt(), posix_info_sid_size() validates (a) at least 2 bytes readable, (b) subauth in [1,15], and (c) beg+total <= end before returning sid_len. This guarantees source-buffer safety. For destination safety, the maximum return value of posix_info_sid_size is 1+1+6+4*15=68 bytes, which exactly equals sizeof(struct cifs_sid) (the type of posix->owner and posix->group). No counterexample can pass all guards and still cause OOB read or write.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 2393
Taint snippetu8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset);
Tainted varsid_len
Sinkmemcpy() line 2409 (arg 2, role=size)
Sink snippetmemcpy(&posix->owner, sid, sid_len);
Possibly guardedyes (heuristic)
Dismissed: sid_len is the return value of posix_info_sid_size(), which (a) verifies sid+sid_len <= end (source buffer safety, where end is within the validated response iov), and (b) is structurally capped at 68 bytes (subauth<=15 => total=1+1+6+60=68), matching sizeof(struct cifs_sid). No counterexample exists: any value passing posix_info_sid_size's guards satisfies both source and destination bounds.

Finding #2 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 2393
Taint snippetu8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset);
Tainted varsid
Sinkmemcpy() line 2409 (arg 1, role=pointer)
Sink snippetmemcpy(&posix->owner, sid, sid_len);
Possibly guardedno
Dismissed: The pointer 'sid' is derived from beg+12 where beg=(u8*)cc+DataOffset. The caller validates DataOffset+DataLength<=rem (within iov). posix_info_sid_size(sid, end) checks sid+2<=end and sid+total<=end before returning, ensuring the read range [sid, sid+sid_len) stays within the validated server buffer. False positive.

Finding #3 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 2393
Taint snippetu8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset);
Tainted varsid_len
Sinkmemcpy() line 2417 (arg 2, role=size)
Sink snippetmemcpy(&posix->group, sid, sid_len);
Possibly guardedyes (heuristic)
Dismissed: Same analysis as finding #1 but for the group SID. posix_info_sid_size() is called again with the updated sid pointer and the same end boundary. sid_len is again bounded to [8,68], and sizeof(posix->group)==sizeof(struct cifs_sid)==68. No OOB write possible.

Finding #4 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 2393
Taint snippetu8 *beg = (u8 *)cc + le16_to_cpu(cc->DataOffset);
Tainted varsid
Sinkmemcpy() line 2417 (arg 1, role=pointer)
Sink snippetmemcpy(&posix->group, sid, sid_len);
Possibly guardedno
Dismissed: Same analysis as finding #2 but for the group SID pointer. After the owner SID memcpy, sid is advanced by owner's sid_len (validated <= end). posix_info_sid_size() then validates the group SID pointer and length against end. All accesses remain within the server buffer bounds established by the caller.

posix_info_parse() — fs/smb/client/smb2pdu.c BUG confidence=high

posix_info_parse() carefully validates that owner_sid and group_sid data fits within the source buffer [beg, end) via posix_info_sid_size(), which returns the total SID byte count. However, it never validates that owner_len or group_len fits within the DESTINATION fields out->owner and out->group. The destination types are fixed-size struct fields (likely struct smb_sid), but posix_info_sid_size() can return up to 1+1+6+4*15=68 bytes (subauth up to 15). If the destination struct fields are smaller than 68 bytes, a server can craft a SID with many sub-authorities to cause an OOB write into adjacent fields of the smb2_posix_info_parsed struct.

Finding #1 — Category B — BUG oob_write

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 5439
Taint snippetend = beg + le32_to_cpu(p->NextEntryOffset);
Tainted varowner_len
Sinkmemcpy() line 5483 (arg 2, role=size)
Sink snippetmemcpy(&out->owner, owner_sid, owner_len);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: KASAN: slab-out-of-bounds in posix_info_parse or heap corruption when copying a server-crafted SID with 15 sub-authorities into out->owner if sizeof(out->owner) < 68
Fix: After posix_info_sid_size() returns owner_len, add: if (owner_len > sizeof(out->owner)) return -1; Similarly for group_len vs sizeof(out->group). This ensures the destination buffer is large enough before the memcpy.
CVE pattern: Server-controlled size used in memcpy without destination bounds check — similar pattern to various SMB2 response parsing OOB writes

Finding #2 — Category B — BUG oob_write

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 5439
Taint snippetend = beg + le32_to_cpu(p->NextEntryOffset);
Tainted vargroup_len
Sinkmemcpy() line 5484 (arg 2, role=size)
Sink snippetmemcpy(&out->group, group_sid, group_len);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: KASAN: slab-out-of-bounds in posix_info_parse or heap corruption when copying a server-crafted group SID with 15 sub-authorities into out->group if sizeof(out->group) < 68
Fix: After posix_info_sid_size() returns group_len, add: if (group_len > sizeof(out->group)) return -1; This ensures the destination buffer is large enough before the memcpy.
CVE pattern: Server-controlled size used in memcpy without destination bounds check — similar to SMB2 response parsing OOB writes

query_info() — fs/smb/client/smb2pdu.c FP confidence=high

The flagged value (le16_to_cpu(rsp->OutputBufferOffset)) is genuinely server-supplied from the SMB2 query info response. However, it is passed directly into smb2_validate_and_copy_iov(), which is itself a validation function: it calls smb2_validate_iov(offset, buffer_length, iov, minbufsize) before performing the memcpy. The memcpy inside smb2_validate_and_copy_iov() is the result of successful validation, not a vulnerable sink. The smb2_validate_iov call checks that offset + buffer_length does not exceed iov->iov_len and that the buffer is large enough, ensuring begin_of_buf and the subsequent memcpy(data, begin_of_buf, minbufsize) are safe. The pattern here is the classic validator-function false positive: the scanner flagged the memcpy inside the validator as a sink, but those accesses are protected by the validation logic immediately preceding them.

Finding #1 — Category A — cross-function via smb2_validate_and_copy_iov() — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 4011
Taint snippetrc = smb2_validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset),
Tainted varle16_to_cpu(rsp->OutputBufferOffset)
Call siteline 4011 — passes le16_to_cpu(rsp->OutputBufferOffset) to smb2_validate_and_copy_iov()
Call snippetrc = smb2_validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset),
Sink (in callee)memcpy() line 3868 (arg 1, role=pointer)
Sink snippetmemcpy(data, begin_of_buf, minbufsize);
Possibly guardedno
Dismissed: smb2_validate_and_copy_iov() calls smb2_validate_iov(offset, buffer_length, iov, minbufsize) before executing the memcpy. smb2_validate_iov verifies that the offset and buffer_length are within the iov bounds and that the minimum buffer size is satisfied. Only if all checks pass does the code reach memcpy(data, begin_of_buf, minbufsize). No counterexample can be constructed because any out-of-range offset or length would cause smb2_validate_iov to return an error, preventing the memcpy. This is a false positive: the memcpy is inside the validation function, after its own internal guard.

smb2_parse_contexts() — fs/smb/client/smb2pdu.c FP confidence=high

The function has a careful multi-layer validation discipline: (1) pre-loop check ensures off+rem fits in iov_len; (2) the loop condition 'rem >= sizeof(*cc)' guarantees struct field reads are in-bounds; (3) per-iteration doff+dlen <= rem check bounds data; (4) noff+nlen <= doff check bounds name within rem; (5) check_sub_overflow on cc->Next maintains rem as a valid remaining-bytes invariant; (6) parse_posix_ctxt uses posix_info_sid_size with 'end' pointer to bound-check SID sizes before memcpy. All flagged accesses are protected by these guards.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 2445
Taint snippetrem = le32_to_cpu(rsp->CreateContextsLength);
Tainted varrem
Loopwhile_loop line 2454
Sink snippetwhile (rem >= sizeof(*cc)) {
Possibly guardedno
Dismissed: rem is validated against rsp_iov->iov_len before the loop (off+rem <= iov_len). The loop condition 'rem >= sizeof(*cc)' provides per-iteration bounds. check_sub_overflow(rem, off, &rem) on cc->Next keeps rem as valid remaining bytes. No counterexample possible: any value of rem that exceeds the buffer would be caught by the pre-loop check.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 2444
Taint snippetoff = le32_to_cpu(rsp->CreateContextsOffset);
Tainted varcc
Pointer derefcc->DataOffset line 2455
Sink snippetdoff = le16_to_cpu(cc->DataOffset);
Possibly guardedno
Dismissed: The loop guard 'rem >= sizeof(*cc)' ensures at least sizeof(struct create_context) bytes are available at cc before any field is read. cc->DataOffset is within that struct, so the read is safe. Cannot construct a counterexample where the guard passes but the field access is OOB.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 2444
Taint snippetoff = le32_to_cpu(rsp->CreateContextsOffset);
Tainted varcc
Pointer derefcc->DataLength line 2456
Sink snippetdlen = le32_to_cpu(cc->DataLength);
Possibly guardedno
Dismissed: Same as finding #2: loop guard ensures sizeof(*cc) bytes available, DataLength is a field within that struct. Protected.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 2444
Taint snippetoff = le32_to_cpu(rsp->CreateContextsOffset);
Tainted varcc
Pointer derefcc->NameOffset line 2460
Sink snippetnoff = le16_to_cpu(cc->NameOffset);
Possibly guardedno
Dismissed: Same as finding #2: loop guard ensures sizeof(*cc) bytes available, NameOffset is a field within that struct. Protected.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 2444
Taint snippetoff = le32_to_cpu(rsp->CreateContextsOffset);
Tainted varcc
Pointer derefcc->NameLength line 2461
Sink snippetnlen = le16_to_cpu(cc->NameLength);
Possibly guardedno
Dismissed: Same as finding #2: loop guard ensures sizeof(*cc) bytes available, NameLength is a field within that struct. Protected.

Finding #6 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele32_to_cpu() line 2444
Taint snippetoff = le32_to_cpu(rsp->CreateContextsOffset);
Tainted varname
Sinkmemcmp() line 2477 (arg 0, role=pointer)
Sink snippetif (posix && !memcmp(name, smb3_create_tag_posix, 16))
Possibly guardedno
Dismissed: name = cc + noff. We have: noff + nlen <= doff (line 2462 check), and doff + dlen <= rem (line 2457 check), so noff + nlen <= rem. With nlen=16 for the memcmp case, name+16 is within the valid rem bytes from cc. Cannot construct a counterexample where these guards pass but memcmp reads beyond the buffer.

Finding #7 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 2444
Taint snippetoff = le32_to_cpu(rsp->CreateContextsOffset);
Tainted varcc
Pointer derefcc->Next line 2488
Sink snippetoff = le32_to_cpu(cc->Next);
Possibly guardedno
Dismissed: cc->Next is read after all per-iteration data validation. The loop guard ensures sizeof(*cc) bytes are available at cc, so reading cc->Next (a field within the struct) is safe. check_sub_overflow(rem, off, &rem) then validates the Next offset doesn't exceed rem.

Finding #8 — Category B — cross-function via parse_posix_ctxt() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 2444
Taint snippetoff = le32_to_cpu(rsp->CreateContextsOffset);
Tainted varcc
Call siteline 2478 — passes cc to parse_posix_ctxt()
Call snippetparse_posix_ctxt(cc, buf, posix);
Sink (in callee)memcpy() line 2409 (arg 2, role=size)
Sink snippetmemcpy(&posix->owner, sid, sid_len);
Possibly guardedyes (heuristic)
Dismissed: In parse_posix_ctxt, beg = cc + DataOffset and end = beg + DataLength. These are bounded by the prior doff+dlen <= rem validation. posix_info_sid_size(sid, end) computes sid_len with 'end' as the upper bound and returns negative if the SID extends beyond 'end'. The early return on sid_len < 0 prevents the memcpy. The size argument to memcpy is thus bounded by [0, dlen]. No counterexample possible.

Finding #9 — Category B — cross-function via parse_posix_ctxt() — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 2444
Taint snippetoff = le32_to_cpu(rsp->CreateContextsOffset);
Tainted varcc
Call siteline 2478 — passes cc to parse_posix_ctxt()
Call snippetparse_posix_ctxt(cc, buf, posix);
Sink (in callee)memcpy() line 2417 (arg 2, role=size)
Sink snippetmemcpy(&posix->group, sid, sid_len);
Possibly guardedyes (heuristic)
Dismissed: Same analysis as finding #8 for the group SID memcpy. posix_info_sid_size advances sid past the owner SID and validates the group SID against end, returning negative if invalid. The early return on sid_len < 0 prevents unsafe memcpy. Protected.

smb311_decode_neg_context() — fs/smb/client/smb2pdu.c FP confidence=high

The function has robust per-iteration bounds checking. The initial offset is validated (len_of_smb > offset), then len_of_ctxts = len_of_smb - offset. Each iteration checks len_of_ctxts >= sizeof(struct smb2_neg_context) before dereferencing pctx, ensuring all field accesses are within bounds. The loop count ctxt_cnt is irrelevant because the per-iteration break guard is sufficient — no matter how large ctxt_cnt is, the loop terminates when the remaining buffer is exhausted. All sub-context decoders also validate their DataLength fields before accessing flexible array members.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 975
Taint snippetunsigned int ctxt_cnt = le16_to_cpu(rsp->NegotiateContextCount);
Tainted varctxt_cnt
Loopfor_loop line 987
Sink snippetfor (i = 0; i < ctxt_cnt; i++) {
Possibly guardedno
Dismissed: Per-iteration guard at line 990 breaks when len_of_ctxts < sizeof(struct smb2_neg_context), effectively capping iterations by available buffer space regardless of ctxt_cnt. Counterexample attempt: ctxt_cnt=65535, len_of_ctxts=0 → loop breaks immediately. No OOB possible.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 974
Taint snippetunsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
Tainted varpctx
Pointer derefpctx->DataLength line 995
Sink snippet+ le16_to_cpu(pctx->DataLength);
Possibly guardedno
Dismissed: Before pctx->DataLength is read at line 995, line 990 ensures len_of_ctxts >= sizeof(struct smb2_neg_context), which means offset + sizeof(struct smb2_neg_context) <= len_of_smb. DataLength is within the struct header so the access is safe.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 974
Taint snippetunsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
Tainted varpctx
Pointer derefpctx->ContextType line 1006
Sink snippetif (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES)
Possibly guardedno
Dismissed: Same protection as finding #2 — line 990 ensures the full smb2_neg_context header (including ContextType) is within bounds before pctx is dereferenced.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 974
Taint snippetunsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
Tainted varpctx
Pointer derefpctx->ContextType line 1009
Sink snippetelse if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES)
Possibly guardedyes (heuristic)
Dismissed: Same ContextType access, same protection from line 990 guard. False positive.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 974
Taint snippetunsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
Tainted varpctx
Pointer derefpctx->ContextType line 1012
Sink snippetelse if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES)
Possibly guardedyes (heuristic)
Dismissed: Same ContextType access, same protection from line 990 guard. False positive.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 974
Taint snippetunsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
Tainted varpctx
Pointer derefpctx->ContextType line 1015
Sink snippetelse if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
Possibly guardedyes (heuristic)
Dismissed: Same ContextType access, same protection from line 990 guard. False positive.

Finding #7 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 974
Taint snippetunsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
Tainted varpctx
Pointer derefpctx->ContextType line 1017
Sink snippetelse if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES)
Possibly guardedyes (heuristic)
Dismissed: Same ContextType access, same protection from line 990 guard. False positive.

Finding #8 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 974
Taint snippetunsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
Tainted varpctx
Pointer derefpctx->ContextType line 1022
Sink snippetle16_to_cpu(pctx->ContextType));
Possibly guardedyes (heuristic)
Dismissed: Same ContextType access in the else branch (debug log), same protection from line 990 guard. False positive.

Finding #9 — Category F — cross-function via decode_compress_ctx() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 974
Taint snippetunsigned int offset = le32_to_cpu(rsp->NegotiateContextOffset);
Tainted varpctx
Call siteline 1013 — passes pctx to decode_compress_ctx()
Call snippetdecode_compress_ctx(server,
Loopfor_loop line 866
Sink snippetfor (i = 0; i < count; i++) {
Possibly guardedyes (heuristic)
Dismissed: decode_compress_ctx() validates count against ARRAY_SIZE(ctxt->CompressionAlgorithms) and checks len >= 8 + count * sizeof(__le16). The len was already bounded by the caller's clen <= len_of_ctxts check. The loop bound is properly validated before use. No OOB possible.

smb2_calc_signature() — fs/smb/client/smb2transport.c FP confidence=high

The static scanner has misidentified the taint flow. The finding claims that `sid` (a 64-bit value from le64_to_cpu) is silently truncated to 32-bit `rc`, but `sid` is only passed as an argument to `smb2_get_sign_key()`. The return value `rc` is the integer return code of that function call — it is NOT a truncation of `sid`. The scanner appears to have incorrectly propagated the taint from `sid` through the function call argument to the return value stored in `rc`. This is a classic taint analysis false positive where taint from a function argument is incorrectly attributed to the function's return value.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele64_to_cpu() line 220
Taint snippetrc = smb2_get_sign_key(server, sid, key);
Tainted varrc
Truncationline 220: 64 → 32-bit u32
Sink snippetrc = smb2_get_sign_key(server, sid, key);
Possibly guardedno
Dismissed: The taint flow is entirely fabricated by the scanner. `sid` (from le64_to_cpu(shdr->SessionId)) is indeed server-supplied and passed to `smb2_get_sign_key(server, sid, key)`. However, `rc` is the INTEGER RETURN CODE of that function, not a truncation of `sid`. The 64-bit `sid` value is passed as a u64 parameter; there is no truncation to 32-bit. The return value `rc` is the function's error code (an int), which is completely independent of the `sid` value. The scanner incorrectly propagated taint from the `sid` argument to the `rc` return value assignment. No counterexample can be constructed because no truncation actually occurs — the types are entirely separate variables with no arithmetic relationship at the flagged line.

smb2_seq_num_into_buf() — fs/smb/client/smb2transport.c FP confidence=high

The shdr pointer comes from a locally-constructed SMB2 request buffer (rqst->rq_iov[0].iov_base), not a server response. The CreditCharge field is written by the kernel when building outgoing requests. Additionally, the loop body only calls get_next_mid(server) which increments an internal counter — there is no buffer indexing or memory access whose bounds could be violated by the iteration count. The finding conflates 'loop iteration count' with 'buffer traversal', but this loop performs no memory traversal.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 602
Taint snippetunsigned int i, num = le16_to_cpu(shdr->CreditCharge);
Tainted varnum
Loopfor_loop line 606
Sink snippetfor (i = 1; i < num; i++)
Possibly guardedno
Dismissed: shdr is extracted from a locally-built SMB2 request (rqst->rq_iov[0].iov_base), so CreditCharge was set by the kernel, not received from a server. Furthermore, the loop body only calls get_next_mid(server) to advance a sequence number counter — it performs no buffer access, so there is no OOB memory hazard regardless of the iteration count. No counterexample for OOB access can be constructed because the loop does not index any buffer.

smb3_calc_signature() — fs/smb/client/smb2transport.c FP confidence=high

The finding misidentifies the taint flow. le64_to_cpu(shdr->SessionId) is passed as an argument to smb3_get_sign_key(), not assigned to 'rc'. The return value 'rc' is an int (error code) from smb3_get_sign_key(), not a truncation of the 64-bit SessionId. There is no truncation of the server-supplied SessionId into 'rc'; 'rc' receives the function's return value which is a standard kernel error code (int). The SessionId is passed as a u64 parameter to smb3_get_sign_key() — no truncation occurs at the call site either, since the parameter type of smb3_get_sign_key() accepts a 64-bit session ID. The scanner incorrectly traced the taint from le64_to_cpu() through the function call return assignment.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele64_to_cpu() line 475
Taint snippetrc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key);
Tainted varrc
Truncationline 475: 64 → 32-bit u32
Sink snippetrc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key);
Possibly guardedno
Dismissed: The scanner incorrectly attributed the taint of le64_to_cpu(shdr->SessionId) to 'rc'. In reality, rc receives the integer return value of smb3_get_sign_key(), which is a standard errno-style int, not a truncation of the 64-bit SessionId. The SessionId is passed as a u64 argument to smb3_get_sign_key() — no narrowing truncation occurs. The rc value is then checked with 'if (unlikely(rc))' which correctly handles all error conditions. No counterexample exists because rc never holds the SessionId value. This is a false positive caused by imprecise taint propagation through function call boundaries.

__release_mid() — fs/smb/client/transport.c FP confidence=high

All array accesses using smb_cmd are uniformly guarded by the check 'if (smb_cmd < NUMBER_OF_SMB2_COMMANDS)' on line 68 (and again on line 98 for the second block). The arrays server->num_cmds[], server->slowest_cmd[], server->fastest_cmd[], server->time_per_cmd[], and server->smb2slowcmd[] are all dimensioned [NUMBER_OF_SMB2_COMMANDS]. Since smb_cmd is a __u16 (unsigned, non-negative) and is checked to be strictly less than NUMBER_OF_SMB2_COMMANDS before every array access, no out-of-bounds access is possible. The scanner flagged these as 'possibly guarded' and the guards are in fact complete and sufficient. No counterexample can be constructed: any smb_cmd >= NUMBER_OF_SMB2_COMMANDS causes an early exit from the if-block before any array indexing occurs.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 69
Sink snippetif (atomic_read(&server->num_cmds[smb_cmd]) == 0) {
Possibly guardedyes (heuristic)
Dismissed: Guard at line 68: 'if (smb_cmd < NUMBER_OF_SMB2_COMMANDS)' strictly bounds smb_cmd before all accesses on lines 69-79. Cannot construct a counterexample: any value >= NUMBER_OF_SMB2_COMMANDS skips the entire block.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 70
Sink snippetserver->slowest_cmd[smb_cmd] = roundtrip_time;
Possibly guardedyes (heuristic)
Dismissed: Same guard as finding #1 protects line 70. No counterexample possible.

Finding #3 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 71
Sink snippetserver->fastest_cmd[smb_cmd] = roundtrip_time;
Possibly guardedyes (heuristic)
Dismissed: Same guard as finding #1 protects line 71. No counterexample possible.

Finding #4 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 73
Sink snippetif (server->slowest_cmd[smb_cmd] < roundtrip_time)
Possibly guardedyes (heuristic)
Dismissed: Same guard as finding #1 protects line 73. No counterexample possible.

Finding #5 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 74
Sink snippetserver->slowest_cmd[smb_cmd] = roundtrip_time;
Possibly guardedyes (heuristic)
Dismissed: Same guard as finding #1 protects line 74. No counterexample possible.

Finding #6 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 75
Sink snippetelse if (server->fastest_cmd[smb_cmd] > roundtrip_time)
Possibly guardedyes (heuristic)
Dismissed: Same guard as finding #1 protects line 75. No counterexample possible.

Finding #7 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 76
Sink snippetserver->fastest_cmd[smb_cmd] = roundtrip_time;
Possibly guardedyes (heuristic)
Dismissed: Same guard as finding #1 protects line 76. No counterexample possible.

Finding #8 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 78
Sink snippetcifs_stats_inc(&server->num_cmds[smb_cmd]);
Possibly guardedyes (heuristic)
Dismissed: Same guard as finding #1 protects line 78. No counterexample possible.

Finding #9 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 79
Sink snippetserver->time_per_cmd[smb_cmd] += roundtrip_time;
Possibly guardedyes (heuristic)
Dismissed: Same guard as finding #1 protects line 79. No counterexample possible.

Finding #10 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 45
Taint snippet__u16 smb_cmd = le16_to_cpu(midEntry->command);
Tainted varsmb_cmd
Subscript[] line 99
Sink snippetcifs_stats_inc(&server->smb2slowcmd[smb_cmd]);
Possibly guardedyes (heuristic)
Dismissed: Guard at line 98 ('if (smb_cmd < NUMBER_OF_SMB2_COMMANDS)') strictly bounds smb_cmd before the access at line 99. No counterexample possible.