Bounds Checker Report — 20260820_151055_net

Date: 2026-08-20 15:20:02 Model: claude-sonnet-4-6 Source: net Files: 1742 Stage 1: 643 findings (Cat A: 16  |  Cat B: 45  |  Cat C: 118  |  Cat E: 233  |  Cat F: 101  |  Cat G2: 64  |  Cat H: 66) Stage 2: 68 real  |  575 FP  |  0 unanalyzed Kernel: v7.2-rc7-32-gaf5a019bf97e Branch: work/fscache-fixes
32 local commit(s) since origin/master
  1. af5a019bf97e cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure
  2. e6a9c11309cd cifs: call pagecache_isize_extended() in cifs_setsize() when extending
  3. 5fce3864d8e5 smb: client: restore the data_offset bound in is_valid_oplock_break()
  4. 7f11fbcc7141 cifs: clear tcon after cifsFileInfo_put() in cifs_file_set_size()
  5. 1e13b07759b9 smb: client: Avoid leaking sensitive data to the heap in connect.c
  6. d91fefcf00b0 smb: client: Clear sensitive stack data in smb1encrypt.c
  7. 24ec30094b95 smb: client: Clear sensitive stack data in cifsencrypt.c
  8. 3e200e7995cc smb: client: Clear sensitive stack and heap data in smb2ops.c
  9. 13881ad0a8d9 smb: client: Clear sensitive stack data in smb2transport.c
  10. 3356da3ae12b Revert "cifs: remove all cifs files before kill super"
  11. 98dfc0f0348c smb: client: fix use-before-check of ReparseDataLength in reparse_buf_ptr()
  12. 442beae405ea smb: client: fix ALIGN() overflow in symlink_data() error context loop
  13. 67b83682e9c5 smb: client: simplify __build_path_from_dentry_optional_prefix()
  14. cb4c026ddc77 smb: client: fix UAF and buffer leak in cifs_check_trans2() for malformed secondary T2
  15. f1e640a65f45 smb: client: fix OOB read/write from unvalidated DataOffset in coalesce_t2()
  16. e56686589295 smb/client: decode reparse metadata using its payload type
  17. 0a09b6270c91 smb/client: preserve open info type across compound queries
  18. c2f17b3a404d smb/client: mark missing nlink values as unknown
  19. 746f8bb16e15 cifs: fix clearing stats for fastest execution of each smb2 command
  20. 7886f8ae3173 smb/client: remove unused file flags ioctl handlers
  21. 1f852aaa3c8c smb/client: implement fileattr_set for compression flags
  22. 77d852c76342 smb/client: fix nlink of an overwritten open file
  23. 60be95527bc8 cifs: remove dead size-update blocks in cifs_setattr_unix/nounix
  24. 297d8026a570 cifs: remove redundant size-update block in cifs_remap_file_range()
  25. 32a7af68df73 cifs: add cifs_resize_file_locked() to guard fscache_resize_cookie() under i_rwsem
  26. 364b18323058 cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC
  27. b1b741cf8e7c smb: client: clear ce->tgthint in free_tgts()
  28. bf86c08123c6 smb: client: harden DFS cache against invalid target hints
  29. b8e5dc4f95e5 smb: client: clear setuid/setgid bit on write with cifsacl/modefromsid/posix extensions
  30. 45f84cf25a08 smb: client: set replay flag on the read send-error retry path
  31. deb6468f4164 smb: client: fix request buffer leak in smb2_new_read_req()
  32. a2f9fb451c68 smb/client: return EOPNOTSUPP for unsupported O_TMPFILE

Contents

net/6lowpan/ (2 functions) — 0 real, 4 FP
net/802/ (1 function) — 0 real, 1 FP
net/atm/ (1 function) — 0 real, 5 FP
net/batman-adv/ (10 functions) — 1 real, 14 FP
net/bluetooth/ (6 functions) — 0 real, 19 FP
net/bluetooth/bnep/ (2 functions) — 0 real, 2 FP
net/bluetooth/ (6 functions) — 0 real, 19 FP
net/bpf/ (5 functions) — 0 real, 6 FP
net/bridge/ (4 functions) — 0 real, 12 FP
net/bridge/netfilter/ (5 functions) — 0 real, 5 FP
net/ceph/ (7 functions) — 3 real, 10 FP
net/ (3 functions) — 0 real, 3 FP
net/core/ (9 functions) — 0 real, 14 FP
net/dsa/ (6 functions) — 1 real, 10 FP
net/ethtool/ (14 functions) — 0 real, 16 FP
net/ieee802154/ (1 function) — 0 real, 1 FP
net/ipv4/ (15 functions) — 0 real, 35 FP
net/ipv4/netfilter/ (4 functions) — 0 real, 4 FP
net/ipv4/ (15 functions) — 0 real, 35 FP
net/ipv6/ (9 functions) — 0 real, 10 FP
net/ipv6/netfilter/ (2 functions) — 0 real, 3 FP
net/ipv6/ (9 functions) — 0 real, 10 FP
net/l2tp/ (3 functions) — 0 real, 3 FP
net/llc/ (2 functions) — 0 real, 4 FP
net/mac80211/ (24 functions) — 0 real, 90 FP
net/mctp/ (2 functions) — 0 real, 2 FP
net/mptcp/ (3 functions) — 0 real, 3 FP
net/netfilter/ipset/ (16 functions) — 0 real, 24 FP
net/netfilter/ipvs/ (5 functions) — 0 real, 13 FP
net/netfilter/ (13 functions) — 2 real, 60 FP
net/netlabel/ (2 functions) — 0 real, 2 FP
net/qrtr/ (1 function) — 0 real, 2 FP
net/rds/ (7 functions) — 3 real, 4 FP
net/rfkill/ (1 function) — 0 real, 1 FP
net/rxrpc/ (9 functions) — 0 real, 24 FP
net/sctp/ (36 functions) — 22 real, 80 FP
sctp_association_init() — associola.c BUG __sctp_auth_cid() — auth.c BUG sctp_auth_asoc_get_hmac() — auth.c MIXED sctp_auth_asoc_set_default_hmac() — auth.c MIXED sctp_auth_asoc_verify_hmac_id() — auth.c BUG sctp_auth_ep_add_chunkid() — auth.c BUG sctp_auth_make_key_vector() — auth.c BUG __sctp_rcv_lookup_endpoint() — input.c FP sctp_acked() — outqueue.c FP sctp_check_transmitted() — outqueue.c FP sctp_outq_flush_data() — outqueue.c FP sctp_outq_sack() — outqueue.c BUG sctp_sack_update_unack_data() — outqueue.c FP sctp_get_asconf_response() — sm_make_chunk.c BUG sctp_pack_cookie() — sm_make_chunk.c FP sctp_process_asconf() — sm_make_chunk.c BUG sctp_process_asconf_ack() — sm_make_chunk.c BUG sctp_process_ext_param() — sm_make_chunk.c BUG sctp_process_param() — sm_make_chunk.c FP sctp_verify_ext_param() — sm_make_chunk.c BUG sctp_verify_param() — sm_make_chunk.c BUG sctp_eat_data() — sm_statefuns.c FP sctp_sf_authenticate() — sm_statefuns.c FP sctp_sf_do_5_1B_init() — sm_statefuns.c FP sctp_sf_do_unexpected_init() — sm_statefuns.c FP sctp_get_port_local() — socket.c FP sctp_getsockopt_hmac_ident() — socket.c FP sctp_getsockopt_local_addrs() — socket.c FP sctp_getsockopt_local_auth_chunks() — socket.c BUG sctp_getsockopt_peer_auth_chunks() — socket.c BUG sctp_process_strreset_addstrm_in() — stream.c FP sctp_process_strreset_addstrm_out() — stream.c FP sctp_process_strreset_inreq() — stream.c FP sctp_process_strreset_outreq() — stream.c MIXED sctp_process_strreset_resp() — stream.c FP sctp_process_strreset_tsnreq() — stream.c FP
net/smc/ (2 functions) — 0 real, 6 FP
net/ (3 functions) — 0 real, 3 FP
net/sunrpc/ (1 function) — 0 real, 1 FP
net/tipc/ (2 functions) — 0 real, 2 FP
net/vmw_vsock/ (1 function) — 0 real, 14 FP
net/wireless/ (8 functions) — 34 real, 57 FP
net/xfrm/ (9 functions) — 2 real, 9 FP

Summary

FunctionFileAssessmentConfidenceRealFPUnanalyzed
net/6lowpan/ — 2 functions, 0 real, 4 FP
lowpan_ctx_pfx_write()net/6lowpan/debugfs.cFPhigh010
udp_compress()net/6lowpan/nhc_udp.cFPhigh030
net/802/ — 1 function, 0 real, 1 FP
mrp_pdu_parse_vecattr()net/802/mrp.cFPhigh010
net/atm/ — 1 function, 0 real, 5 FP
atm_dev_ioctl()net/atm/resources.cFPhigh050
net/batman-adv/ — 10 functions, 1 real, 14 FP
batadv_v_ogm_forward()net/batman-adv/bat_v_ogm.cFPhigh040
batadv_v_ogm_process_per_outif()net/batman-adv/bat_v_ogm.cBUGmedium100
batadv_frag_insert_packet()net/batman-adv/fragmentation.cFPhigh020
batadv_frag_merge_packets()net/batman-adv/fragmentation.cFPmedium020
batadv_recv_mcast_packet()net/batman-adv/routing.cFPhigh010
batadv_recv_unicast_tvlv()net/batman-adv/routing.cFPhigh010
batadv_send_other_tt_response()net/batman-adv/translation-table.cFPhigh010
batadv_tvlv_container_ogm_append()net/batman-adv/tvlv.cFPhigh010
batadv_tvlv_container_register()net/batman-adv/tvlv.cFPhigh010
batadv_tvlv_ogm_receive()net/batman-adv/tvlv.cFPmedium010
net/bluetooth/ — 6 functions, 0 real, 19 FP
lowpan_control_write()net/bluetooth/6lowpan.cFPhigh010
net/bluetooth/bnep/ — 2 functions, 0 real, 2 FP
bnep_ctrl_set_mcfilter()net/bluetooth/bnep/core.cFPhigh010
bnep_ctrl_set_netfilter()net/bluetooth/bnep/core.cFPhigh010
net/bluetooth/ — 6 functions, 0 real, 19 FP
hci_get_conn_list()net/bluetooth/hci_conn.cFPhigh010
force_no_mitm_write()net/bluetooth/hci_debugfs.cFPhigh010
hci_le_per_adv_report_evt()net/bluetooth/hci_event.cFPhigh050
hci_sock_sendmsg()net/bluetooth/hci_sock.cFPhigh010
send_hci_cmd_sync()net/bluetooth/mgmt.cFPhigh0100
net/bpf/ — 5 functions, 0 real, 6 FP
bpf_ctx_finish()net/bpf/test_run.cFPhigh010
bpf_ctx_init()net/bpf/test_run.cFPhigh010
bpf_prog_test_run_skb()net/bpf/test_run.cFPhigh010
bpf_prog_test_run_xdp()net/bpf/test_run.cFPhigh010
bpf_test_finish()net/bpf/test_run.cFPhigh020
net/bridge/ — 4 functions, 0 real, 12 FP
br_ioctl_stub()net/bridge/br_ioctl.cFPhigh010
old_deviceless()net/bridge/br_ioctl.cFPhigh010
br_ip4_multicast_igmp3_report()net/bridge/br_multicast.cFPhigh080
br_ip6_multicast_mld2_report()net/bridge/br_multicast.cFPhigh020
net/bridge/netfilter/ — 5 functions, 0 real, 5 FP
ebt_vlan_mt()net/bridge/netfilter/ebt_vlan.cFPhigh010
compat_do_replace()net/bridge/netfilter/ebtables.cFPhigh010
compat_match_to_user()net/bridge/netfilter/ebtables.cFPhigh010
compat_target_to_user()net/bridge/netfilter/ebtables.cFPhigh010
ebt_obj_to_user()net/bridge/netfilter/ebtables.cFPhigh010
net/ceph/ — 7 functions, 3 real, 10 FP
encrypt_authorizer()net/ceph/auth_x.cFPhigh060
ceph_alloc_middle()net/ceph/messenger.cVALIDATEmedium100
alloc_msg_with_page_vector()net/ceph/osd_client.cBUGhigh200
get_reply()net/ceph/osd_client.cFPhigh010
handle_reply()net/ceph/osd_client.cFPhigh010
osd_sparse_read()net/ceph/osd_client.cFPhigh010
prep_next_sparse_read()net/ceph/osd_client.cFPhigh010
net/ — 3 functions, 0 real, 3 FP
cmsghdr_from_user_compat_to_kern()net/compat.cFPhigh010
put_cmsg_compat()net/compat.cFPhigh010
net/core/ — 9 functions, 0 real, 14 FP
netdev_cmd_to_name()net/core/dev.cFPhigh010
ptype_head()net/core/dev.cFPhigh010
__get_filter()net/core/filter.cFPhigh010
bpf_prog_create_from_user()net/core/filter.cFPhigh010
ptype_seq_next()net/core/net-procfs.cFPhigh020
pf()net/core/pktgen.cFPhigh040
skb_checksum_setup_ipv6()net/core/skbuff.cFPhigh010
skb_mpls_dec_ttl()net/core/skbuff.cFPhigh010
sock_ioctl_inout()net/core/sock.cFPhigh020
net/dsa/ — 6 functions, 1 real, 10 FP
ar9331_tag_rcv()net/dsa/tag_ar9331.cFPhigh020
ksz_xmit_timestamp()net/dsa/tag_ksz.cFPhigh010
qca_tag_rcv()net/dsa/tag_qca.cFPhigh020
rtl4a_tag_rcv()net/dsa/tag_rtl4_a.cFPhigh020
rtl8_4_read_tag()net/dsa/tag_rtl8_4.cFPhigh030
sja1110_rcv_inband_control_extension()net/dsa/tag_sja1105.cBUGmedium100
net/ethtool/ — 14 functions, 0 real, 16 FP
ethtool_cmis_cdb_execute_epl_cmd()net/ethtool/cmis_cdb.cFPmedium020
ethtool_copy_validate_indir()net/ethtool/ioctl.cFPhigh010
ethtool_get_dump_data()net/ethtool/ioctl.cFPhigh010
ethtool_get_features()net/ethtool/ioctl.cFPhigh010
ethtool_get_phy_stats()net/ethtool/ioctl.cFPmedium010
ethtool_get_sset_info()net/ethtool/ioctl.cFPhigh010
ethtool_get_stats()net/ethtool/ioctl.cFPhigh010
ethtool_get_tunable()net/ethtool/ioctl.cFPhigh010
ethtool_rxnfc_copy_from_compat()net/ethtool/ioctl.cFPhigh010
ethtool_rxnfc_copy_from_user()net/ethtool/ioctl.cFPhigh010
ethtool_rxnfc_copy_to_compat()net/ethtool/ioctl.cFPhigh010
ethtool_rxnfc_copy_to_user()net/ethtool/ioctl.cFPhigh020
ethtool_self_test()net/ethtool/ioctl.cFPhigh010
get_phy_tunable()net/ethtool/ioctl.cFPhigh010
net/ieee802154/ — 1 function, 0 real, 1 FP
dgram_getsockopt()net/ieee802154/socket.cFPhigh010
net/ipv4/ — 15 functions, 0 real, 35 FP
cipso_v4_map_cat_enum_ntoh()net/ipv4/cipso_ipv4.cFPhigh010
cipso_v4_map_cat_rng_ntoh()net/ipv4/cipso_ipv4.cFPhigh020
rtentry_to_fib_config()net/ipv4/fib_frontend.cFPhigh010
fib_table_insert()net/ipv4/fib_trie.cFPhigh010
fib_table_lookup()net/ipv4/fib_trie.cFPhigh010
icmp_build_probe()net/ipv4/icmp.cFPhigh0180
igmp_heard_query()net/ipv4/igmp.cFPhigh010
tcp_v4_early_demux()net/ipv4/ip_input.cFPhigh010
ic_bootp_recv()net/ipv4/ipconfig.cFPmedium020
net/ipv4/netfilter/ — 4 functions, 0 real, 4 FP
__do_replace()net/ipv4/netfilter/arp_tables.cFPhigh010
__do_replace()net/ipv4/netfilter/ip_tables.cFPhigh010
pptp_inbound_pkt()net/ipv4/netfilter/nf_nat_pptp.cFPhigh010
pptp_outbound_pkt()net/ipv4/netfilter/nf_nat_pptp.cFPhigh010
net/ipv4/ — 15 functions, 0 real, 35 FP
__cookie_v4_check()net/ipv4/syncookies.cFPhigh010
tcp_v4_err()net/ipv4/tcp_ipv4.cFPhigh010
tcp4_check_fraglist_gro()net/ipv4/tcp_offload.cFPhigh010
__udp4_lib_lookup()net/ipv4/udp.cFPhigh020
__udp4_lib_mcast_deliver()net/ipv4/udp.cFPhigh010
__udp4_lib_mcast_demux_lookup()net/ipv4/udp.cFPhigh010
net/ipv6/ — 9 functions, 0 real, 10 FP
esp6_find_tcp_sk()net/ipv6/esp6.cFPhigh010
tcp_v6_early_demux()net/ipv6/ip6_input.cFPhigh010
net/ipv6/netfilter/ — 2 functions, 0 real, 3 FP
__do_replace()net/ipv6/netfilter/ip6_tables.cFPhigh010
nf_tproxy_get_sock_v6()net/ipv6/netfilter/nf_tproxy_ipv6.cFPhigh020
net/ipv6/ — 9 functions, 0 real, 10 FP
do_rawv6_getsockopt()net/ipv6/raw.cFPhigh010
ipip6_tunnel_get_prl()net/ipv6/sit.cFPhigh010
__cookie_v6_check()net/ipv6/syncookies.cFPhigh010
tcp_v6_err()net/ipv6/tcp_ipv6.cFPhigh010
tcp6_check_fraglist_gro()net/ipv6/tcpv6_offload.cFPhigh010
__udp6_lib_lookup()net/ipv6/udp.cFPhigh020
__udp6_lib_mcast_deliver()net/ipv6/udp.cFPhigh010
net/l2tp/ — 3 functions, 0 real, 3 FP
l2tp_udp_encap_recv()net/l2tp/l2tp_core.cFPhigh010
l2tp_ip_recv()net/l2tp/l2tp_ip.cFPhigh010
l2tp_ip6_recv()net/l2tp/l2tp_ip6.cFPhigh010
net/llc/ — 2 functions, 0 real, 4 FP
llc_sap_action_send_test_r()net/llc/llc_s_ac.cFPhigh020
llc_station_ac_send_test_r()net/llc/llc_station.cFPhigh020
net/mac80211/ — 24 functions, 0 real, 90 FP
ieee80211_process_addba_request()net/mac80211/agg-rx.cFPhigh050
ieee80211_process_addba_resp()net/mac80211/agg-tx.cFPhigh040
ieee80211_rx_uhr_link_reconfig_req()net/mac80211/ap.cFPhigh030
ieee80211_eht_cap_ie_to_sta_eht_cap()net/mac80211/eht.cFPmedium020
ieee80211_process_delba()net/mac80211/ht.cFPhigh040
ieee80211_mesh_rx_bcn_presp()net/mac80211/mesh.cFPhigh080
mesh_rmc_check()net/mac80211/mesh.cFPhigh030
mesh_process_plink_frame()net/mac80211/mesh_plink.cFPhigh010
ieee80211_assoc_config_link()net/mac80211/mlme.cFPhigh050
ieee80211_max_rx_chains()net/mac80211/mlme.cFPhigh020
ieee80211_ml_epcs()net/mac80211/mlme.cFPhigh050
ieee80211_ml_reconfiguration()net/mac80211/mlme.cFPhigh050
ieee80211_rx_mgmt_assoc_resp()net/mac80211/mlme.cFPhigh010
ieee80211_rx_mgmt_beacon()net/mac80211/mlme.cFPhigh090
ieee80211_verify_peer_he_mcs_support()net/mac80211/mlme.cFPhigh030
ieee80211_verify_sta_he_mcs_support()net/mac80211/mlme.cFPhigh030
ieee80211_verify_sta_vht_mcs_support()net/mac80211/mlme.cFPhigh030
ieee80211_rx_h_ctrl()net/mac80211/rx.cFPhigh010
ieee80211_rx_h_defragment()net/mac80211/rx.cFPhigh020
ieee80211_sta_nss_capability()net/mac80211/sta_info.cFPhigh030
__ieee80211_tx_status()net/mac80211/status.cFPhigh030
tkip_mixing_phase1()net/mac80211/tkip.cFPhigh050
tkip_mixing_phase2()net/mac80211/tkip.cFPhigh060
ieee80211_apply_vhtcap_overrides()net/mac80211/vht.cFPhigh040
net/mctp/ — 2 functions, 0 real, 2 FP
mctp_ioctl_tag_copy_from_user()net/mctp/af_mctp.cFPhigh010
mctp_ioctl_tag_copy_to_user()net/mctp/af_mctp.cFPhigh010
net/mptcp/ — 3 functions, 0 real, 3 FP
mptcp_get_subflow_data()net/mptcp/sockopt.cFPhigh010
mptcp_put_full_info()net/mptcp/sockopt.cFPhigh010
mptcp_put_subflow_data()net/mptcp/sockopt.cFPhigh010
net/netfilter/ipset/ — 16 functions, 0 real, 24 FP
ip_set_sockfn_get()net/netfilter/ipset/ip_set_core.cFPhigh010
hash_ip4_uadt()net/netfilter/ipset/ip_set_hash_ip.cFPhigh010
hash_ipmark4_uadt()net/netfilter/ipset/ip_set_hash_ipmark.cFPhigh010
hash_ipport4_uadt()net/netfilter/ipset/ip_set_hash_ipport.cFPhigh020
hash_ipport6_uadt()net/netfilter/ipset/ip_set_hash_ipport.cFPhigh010
hash_ipportip4_uadt()net/netfilter/ipset/ip_set_hash_ipportip.cFPhigh020
hash_ipportip6_uadt()net/netfilter/ipset/ip_set_hash_ipportip.cFPhigh010
hash_ipportnet4_uadt()net/netfilter/ipset/ip_set_hash_ipportnet.cFPhigh030
hash_ipportnet6_uadt()net/netfilter/ipset/ip_set_hash_ipportnet.cFPhigh010
hash_net4_uadt()net/netfilter/ipset/ip_set_hash_net.cFPhigh010
hash_netiface4_uadt()net/netfilter/ipset/ip_set_hash_netiface.cFPhigh010
hash_netnet4_uadt()net/netfilter/ipset/ip_set_hash_netnet.cFPhigh020
hash_netport4_uadt()net/netfilter/ipset/ip_set_hash_netport.cFPhigh020
hash_netport6_uadt()net/netfilter/ipset/ip_set_hash_netport.cFPhigh010
hash_netportnet4_uadt()net/netfilter/ipset/ip_set_hash_netportnet.cFPhigh030
hash_netportnet6_uadt()net/netfilter/ipset/ip_set_hash_netportnet.cFPhigh010
net/netfilter/ipvs/ — 5 functions, 0 real, 13 FP
do_ip_vs_get_ctl()net/netfilter/ipvs/ip_vs_ctl.cFPhigh010
set_sctp_state()net/netfilter/ipvs/ip_vs_proto_sctp.cFPhigh090
ip_vs_proc_sync_conn()net/netfilter/ipvs/ip_vs_sync.cFPhigh010
ip_vs_process_message()net/netfilter/ipvs/ip_vs_sync.cFPhigh010
ip_vs_process_message_v0()net/netfilter/ipvs/ip_vs_sync.cFPhigh010
net/netfilter/ — 13 functions, 2 real, 60 FP
conntrack_pptp_help()net/netfilter/nf_conntrack_pptp.cFPhigh010
hash_by_src()net/netfilter/nf_nat_core.cFPhigh010
nf_tables_delchain()net/netfilter/nf_tables_api.cFPhigh010
nf_tables_newchain()net/netfilter/nf_tables_api.cFPhigh020
nf_tables_newobj()net/netfilter/nf_tables_api.cFPhigh030
nf_tables_newrule()net/netfilter/nf_tables_api.cFPhigh0140
nf_tables_newset()net/netfilter/nf_tables_api.cFPhigh0310
nfnl_cthelper_parse_expect_policy()net/netfilter/nfnetlink_cthelper.cFPhigh010
nfnl_hook_dump_start()net/netfilter/nfnetlink_hook.cFPhigh040
nft_cmp_select_ops()net/netfilter/nft_cmp.cBUGmedium100
nft_reg_to_type()net/netfilter/nft_immediate.cBUGmedium100
xt_data_to_user()net/netfilter/x_tables.cFPhigh010
xt_obj_to_user()net/netfilter/x_tables.cFPhigh010
net/netlabel/ — 2 functions, 0 real, 2 FP
netlbl_af4list_audit_addr()net/netlabel/netlabel_addrlist.cFPhigh010
netlbl_af6list_audit_addr()net/netlabel/netlabel_addrlist.cFPhigh010
net/qrtr/ — 1 function, 0 real, 2 FP
qrtr_ns_worker()net/qrtr/ns.cMIXEDhigh020
net/rds/ — 7 functions, 3 real, 4 FP
rds_add_bound()net/rds/bind.cFPhigh010
rds_cong_clear_bit()net/rds/cong.cBUGhigh010
rds_cong_set_bit()net/rds/cong.cBUGhigh100
rds_cong_test_bit()net/rds/cong.cFPhigh010
rds_ib_inc_copy_to_user()net/rds/ib_recv.cBUGmedium100
rds_ib_xmit()net/rds/ib_send.cFPhigh010
rds_message_inc_copy_to_user()net/rds/message.cBUGmedium100
net/rfkill/ — 1 function, 0 real, 1 FP
rfkill_fop_read()net/rfkill/core.cFPhigh010
net/rxrpc/ — 9 functions, 0 real, 24 FP
rxrpc_preparse_xdr()net/rxrpc/key.cFPhigh090
rxrpc_preparse_xdr_rxkad()net/rxrpc/key.cFPhigh020
rxrpc_preparse_xdr_yfs_rxgk()net/rxrpc/key.cFPhigh030
rxgk_verify_authenticator()net/rxrpc/rxgk.cFPhigh010
rxgk_verify_response()net/rxrpc/rxgk.cFPhigh010
rxgk_yfs_decode_ticket()net/rxrpc/rxgk_app.cFPhigh050
rxkad_verify_packet()net/rxrpc/rxkad.cFPhigh010
rxkad_verify_packet_1()net/rxrpc/rxkad.cFPhigh010
rxkad_verify_packet_2()net/rxrpc/rxkad.cFPhigh010
net/sctp/ — 36 functions, 22 real, 80 FP
sctp_association_init()net/sctp/associola.cBUGhigh200
__sctp_auth_cid()net/sctp/auth.cBUGhigh100
sctp_auth_asoc_get_hmac()net/sctp/auth.cMIXEDhigh120
sctp_auth_asoc_set_default_hmac()net/sctp/auth.cMIXEDhigh110
sctp_auth_asoc_verify_hmac_id()net/sctp/auth.cBUGmedium100
sctp_auth_ep_add_chunkid()net/sctp/auth.cBUGhigh100
sctp_auth_make_key_vector()net/sctp/auth.cBUGhigh390
__sctp_rcv_lookup_endpoint()net/sctp/input.cFPhigh010
sctp_acked()net/sctp/outqueue.cFPmedium020
sctp_check_transmitted()net/sctp/outqueue.cFPhigh010
sctp_outq_flush_data()net/sctp/outqueue.cFPhigh010
sctp_outq_sack()net/sctp/outqueue.cBUGhigh100
sctp_sack_update_unack_data()net/sctp/outqueue.cFPmedium010
sctp_get_asconf_response()net/sctp/sm_make_chunk.cBUGhigh100
sctp_pack_cookie()net/sctp/sm_make_chunk.cFPmedium010
sctp_process_asconf()net/sctp/sm_make_chunk.cBUGmedium100
sctp_process_asconf_ack()net/sctp/sm_make_chunk.cBUGmedium410
sctp_process_ext_param()net/sctp/sm_make_chunk.cBUGhigh100
sctp_process_param()net/sctp/sm_make_chunk.cFPhigh010
sctp_verify_ext_param()net/sctp/sm_make_chunk.cBUGhigh100
sctp_verify_param()net/sctp/sm_make_chunk.cBUGhigh100
sctp_eat_data()net/sctp/sm_statefuns.cFPhigh010
sctp_sf_authenticate()net/sctp/sm_statefuns.cFPmedium020
sctp_sf_do_5_1B_init()net/sctp/sm_statefuns.cFPhigh040
sctp_sf_do_unexpected_init()net/sctp/sm_statefuns.cFPhigh040
sctp_get_port_local()net/sctp/socket.cFPhigh010
sctp_getsockopt_hmac_ident()net/sctp/socket.cFPmedium010
sctp_getsockopt_local_addrs()net/sctp/socket.cFPhigh010
sctp_getsockopt_local_auth_chunks()net/sctp/socket.cBUGhigh100
sctp_getsockopt_peer_auth_chunks()net/sctp/socket.cBUGmedium100
sctp_process_strreset_addstrm_in()net/sctp/stream.cFPhigh020
sctp_process_strreset_addstrm_out()net/sctp/stream.cFPhigh020
sctp_process_strreset_inreq()net/sctp/stream.cFPhigh0100
sctp_process_strreset_outreq()net/sctp/stream.cMIXEDmedium0150
sctp_process_strreset_resp()net/sctp/stream.cFPhigh090
sctp_process_strreset_tsnreq()net/sctp/stream.cFPhigh070
net/smc/ — 2 functions, 0 real, 6 FP
smc_clc_msg_hdr_valid()net/smc/smc_clc.cFPmedium040
smc_rtoken_set()net/smc/smc_core.cFPhigh020
net/ — 3 functions, 0 real, 3 FP
put_user_ifreq()net/socket.cFPhigh010
net/sunrpc/ — 1 function, 0 real, 1 FP
rpc_pipe_generic_upcall()net/sunrpc/rpc_pipe.cFPhigh010
net/tipc/ — 2 functions, 0 real, 2 FP
tipc_nl_compat_name_table_dump_header()net/tipc/netlink_compat.cFPhigh010
tipc_rcv()net/tipc/node.cFPhigh010
net/vmw_vsock/ — 1 function, 0 real, 14 FP
virtio_transport_build_skb()net/vmw_vsock/virtio_transport_common.cFPhigh0140
net/wireless/ — 8 functions, 34 real, 57 FP
nl80211_send_iftype_data()net/wireless/nl80211.cFPhigh010
__regdb_query_wmm()net/wireless/reg.cBUGhigh680
regdb_query_country()net/wireless/reg.cMIXEDmedium20320
set_wmm_rule()net/wireless/reg.cBUGmedium800
valid_country()net/wireless/reg.cFPhigh0100
cfg80211_parse_ml_elem_sta_data()net/wireless/scan.cFPhigh030
cfg80211_get_p2p_attr()net/wireless/util.cFPhigh010
ioctl_private_iw_point()net/wireless/wext-priv.cFPhigh020
net/xfrm/ — 9 functions, 2 real, 9 FP
xfrm_input()net/xfrm/xfrm_input.cFPhigh010
xfrmi4_err()net/xfrm/xfrm_interface_core.cFPhigh010
xfrmi6_err()net/xfrm/xfrm_interface_core.cFPhigh010
__input_process_payload()net/xfrm/xfrm_iptfs.cFPhigh010
iptfs_input_ordered()net/xfrm/xfrm_iptfs.cFPhigh010
xfrm_replay_advance_bmp()net/xfrm/xfrm_replay.cMIXEDmedium110
xfrm_replay_advance_esn()net/xfrm/xfrm_replay.cMIXEDhigh110
xfrm_replay_check_bmp()net/xfrm/xfrm_replay.cFPhigh010
xfrm_replay_check_esn()net/xfrm/xfrm_replay.cFPhigh010

Function Details

lowpan_ctx_pfx_write() — net/6lowpan/debugfs.c FP confidence=high

The flagged 'count' parameter is the standard VFS write syscall size argument, which is user-controlled in the sense that it comes from the write(2) syscall. However, the copy_from_user() call uses min_t(size_t, sizeof(buf) - 1, count) as the size argument, which clamps the copy length to at most sizeof(buf)-1 = 127 bytes regardless of the user-supplied count. The destination buffer 'buf' is a 128-byte stack array, so the copy is always safe. The scanner incorrectly treats the result of min_t() as tainted because 'count' is one of its inputs, but min_t guarantees the result never exceeds sizeof(buf)-1. No counterexample can be constructed that would cause an OOB write because min_t's upper bound is sizeof(buf)-1=127 < sizeof(buf)=128.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 135
Taint snippetif (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1,
Tainted varmin_t(size_t, sizeof(buf) - 1, count)
Unvalidated sizecopy_from_user() arg 2 line 135 — size min_t(size_t, sizeof(buf) - 1, count)
Sink snippetif (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1,
Possibly guardedno
Dismissed: The size passed to copy_from_user is min_t(size_t, sizeof(buf) - 1, count), which evaluates to at most 127 regardless of the user-supplied 'count'. The destination buffer is 128 bytes. No counterexample exists where this causes an OOB write: for any value of count, the copy is bounded to 127 bytes into a 128-byte buffer. This is a textbook correct pattern for debugfs write handlers. The scanner false-positives because it tracks 'count' as tainted through min_t without modeling min_t's bounding semantics.

udp_compress() — net/6lowpan/nhc_udp.c FP confidence=high

All three truncations are guarded by preceding conditional checks that constrain the subtracted value to fit within u8. For finding #1, the 4-bit mask check ensures dest and source offsets are each in [0,15], so the combined byte is at most 255. For findings #2 and #3, the 8-bit mask check ensures the port offset is in [0,255], exactly fitting u8. The scanner did not account for the mathematical postconditions established by the mask comparisons.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 129
Taint snippettmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
Tainted vartmp
Truncationline 129: 16 → 8-bit u8
Sink snippettmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
Possibly guardedno
Dismissed: The guard `(ntohs(uh->dest) & 0xFFF0) == 0xF0B0` constrains dest to [0xF0B0, 0xF0BF], making dest-LOWPAN_NHC_UDP_4BIT_PORT in [0,15]. Similarly source offset is in [0,15]. Combined: tmp in [0,255] — no counterexample exists that passes the guard and overflows u8.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 141
Taint snippettmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
Tainted vartmp
Truncationline 141: 16 → 8-bit u8
Sink snippettmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
Possibly guardedno
Dismissed: The guard `(ntohs(uh->dest) & 0xFF00) == 0xF000` constrains dest to [0xF000, 0xF0FF], making the subtraction result in [0,255] — exactly the u8 range. No counterexample can pass the guard and overflow.

Finding #3 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 150
Taint snippettmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
Tainted vartmp
Truncationline 150: 16 → 8-bit u8
Sink snippettmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
Possibly guardedno
Dismissed: The guard `(ntohs(uh->source) & 0xFF00) == 0xF000` constrains source to [0xF000, 0xF0FF], making the subtraction result in [0,255] — exactly the u8 range. No counterexample can pass the guard and overflow.

mrp_pdu_parse_vecattr() — net/802/mrp.c FP confidence=high

mrp_pdu_parse_vecattr() reads valen from a network packet (genuinely server-supplied), but the while loop that uses valen as an iteration count is protected by a per-iteration call to skb_copy_bits(), which validates that [offset, offset+1) lies within skb->len before each byte read. A large valen cannot cause out-of-bounds memory access because the loop body will return -1 as soon as the skb is exhausted. No counterexample could be constructed that passes all guards yet causes OOB access.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcebe16_to_cpu() line 703
Taint snippetvalen = be16_to_cpu(get_unaligned(&mrp_cb(skb)->vah->lenflags) &
Tainted varvalen
Loopwhile_loop line 729
Sink snippetwhile (valen > 0) {
Possibly guardedyes (heuristic)
Dismissed: Per-iteration protection via skb_copy_bits() at line 730 returns -1 if the skb is exhausted, terminating the loop safely. Could not construct a counterexample: any valen exceeding the remaining packet bytes causes skb_copy_bits() to return < 0 before any out-of-bounds read. The attrvalue buffer used in mrp_attrvalue_inc() is validated before the loop at lines 718-723 and is not affected by valen.

atm_dev_ioctl() — net/atm/resources.c FP confidence=high

All five findings are false positives. The 'size' variable in each case is set to a compile-time constant (strlen(dev->type)+1 from a kernel-internal string, ESI_LEN constant, sizeof(struct atm_dev_stats), sizeof(struct atm_cirange), sizeof(int)) or to a macro constant (ESI_LEN). None of these values are read from user space or a network buffer — they are kernel-internal computations. The static analyzer incorrectly propagated taint from the copy_to_user/copy_from_user call itself (treating the return value or associated variables as tainted) rather than identifying a genuine user-controlled size. The size arguments to all copy operations in this function are fixed compile-time constants or kernel-controlled values, not user-supplied sizes.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 237
Taint snippetif (copy_to_user(buf, dev->type, size)) {
Tainted varsize
Unvalidated sizecopy_to_user() arg 2 line 237 — size size
Sink snippetif (copy_to_user(buf, dev->type, size)) {
Possibly guardedno
Dismissed: size = strlen(dev->type) + 1 is computed from a kernel-internal string field (dev->type is set by the ATM driver, not user-supplied). The taint source is misidentified — the scanner appears to have tainted 'size' because it appears in the same copy_to_user call, not because it was read from user space. No genuine vulnerability.

Finding #2 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 244
Taint snippetif (copy_to_user(buf, dev->esi, size)) {
Tainted varsize
Unvalidated sizecopy_to_user() arg 2 line 244 — size size
Sink snippetif (copy_to_user(buf, dev->esi, size)) {
Possibly guardedno
Dismissed: size = ESI_LEN is a compile-time constant macro, not user-supplied. The scanner incorrectly propagated taint to 'size' from the copy_to_user call context. False positive.

Finding #3 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 268
Taint snippetif (copy_from_user(esi, buf, ESI_LEN)) {
Tainted varESI_LEN
Unvalidated sizecopy_from_user() arg 2 line 268 — size ESI_LEN
Sink snippetif (copy_from_user(esi, buf, ESI_LEN)) {
Possibly guardedno
Dismissed: ESI_LEN is a compile-time constant used as the size argument to copy_from_user. The destination 'esi' is a stack-allocated array of exactly ESI_LEN bytes. This is safe by construction. The scanner incorrectly flagged a constant as user-controlled.

Finding #4 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 290
Taint snippetif (copy_to_user(buf, &dev->ci_range, size)) {
Tainted varsize
Unvalidated sizecopy_to_user() arg 2 line 290 — size size
Sink snippetif (copy_to_user(buf, &dev->ci_range, size)) {
Possibly guardedno
Dismissed: size = sizeof(struct atm_cirange) is a compile-time constant. Not user-supplied. False positive.

Finding #5 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 297
Taint snippetif (copy_to_user(buf, &dev->link_rate, size)) {
Tainted varsize
Unvalidated sizecopy_to_user() arg 2 line 297 — size size
Sink snippetif (copy_to_user(buf, &dev->link_rate, size)) {
Possibly guardedno
Dismissed: size = sizeof(int) is a compile-time constant. Not user-supplied. False positive.

batadv_v_ogm_forward() — net/batman-adv/bat_v_ogm.c FP confidence=high

The scanner misidentifies ogm_forward as a pointer derived from an ntohs() offset. In reality, ogm_forward is cast from skb_buff, which is the base of a freshly allocated SKB data region of size BATADV_OGM2_HLEN + tvlv_len. The accessed fields (throughput, ttl) are within the fixed struct batadv_ogm2_packet header at offset 0, which is always fully present since BATADV_OGM2_HLEN is unconditionally added to the allocation. No OOB access is possible for the header field accesses. The taint propagates through packet_len but does not create a pointer offset by the server-supplied value.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 583
Taint snippettvlv_len = ntohs(ogm_received->tvlv_len);
Tainted varogm_forward
Pointer derefogm_forward->throughput line 596
Sink snippetogm_forward->throughput = htonl(neigh_ifinfo->bat_v.throughput);
Possibly guardedno
Dismissed: ogm_forward points to the start of a locally allocated SKB region of size BATADV_OGM2_HLEN+tvlv_len. Accessing ogm_forward->throughput is within the fixed header (BATADV_OGM2_HLEN bytes always allocated). Cannot construct a counterexample where tvlv_len causes this access to be OOB — the header is always present at offset 0.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 583
Taint snippettvlv_len = ntohs(ogm_received->tvlv_len);
Tainted varogm_forward
Pointer derefogm_forward->ttl line 597
Sink snippetogm_forward->ttl--;
Possibly guardedno
Dismissed: Same reasoning as finding #1. ogm_forward->ttl is within the fixed batadv_ogm2_packet header, always safely allocated. No counterexample possible.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 583
Taint snippettvlv_len = ntohs(ogm_received->tvlv_len);
Tainted varogm_forward
Pointer derefogm_forward->throughput line 601
Sink snippetif_outgoing->net_dev->name, ntohl(ogm_forward->throughput),
Possibly guardedno
Dismissed: Same as finding #1. Reading ogm_forward->throughput for debug output after it was already written at line 596 is safe for the same structural reasons.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 583
Taint snippettvlv_len = ntohs(ogm_received->tvlv_len);
Tainted varogm_forward
Pointer derefogm_forward->ttl line 602
Sink snippetogm_forward->ttl, if_incoming->net_dev->name);
Possibly guardedno
Dismissed: Same as finding #2. Reading ogm_forward->ttl for debug output is safe; it is within the fixed-size header always present in the allocation.

batadv_v_ogm_process_per_outif() — net/batman-adv/bat_v_ogm.c BUG confidence=medium

The function passes a server-supplied tvlv_len directly to batadv_tvlv_containers_process() without validating that it fits within the actual remaining SKB buffer. The callee's internal checks only validate claimed lengths against each other, not against the true packet boundary.

Finding #1 — Category F — cross-function via batadv_tvlv_containers_process() — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 823
Taint snippetbatadv_tvlv_containers_process(bat_priv, BATADV_OGM2, orig_node,
Tainted varntohs(ogm2->tvlv_len)
Call siteline 823 — passes ntohs(ogm2->tvlv_len) to batadv_tvlv_containers_process()
Call snippetbatadv_tvlv_containers_process(bat_priv, BATADV_OGM2, orig_node,
Loopwhile_loop line 514
Sink snippetwhile (tvlv_value_len >= sizeof(*tvlv_hdr)) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in batadv_tvlv_containers_process when processing a malformed OGM2 packet with an inflated tvlv_len field, causing reads beyond the SKB data buffer
Fix: Before calling batadv_tvlv_containers_process(), validate that ntohs(ogm2->tvlv_len) does not exceed the actual remaining packet data: compute max_tvlv_len = skb->len - ogm_offset - sizeof(*ogm2) and drop/clamp if ntohs(ogm2->tvlv_len) > max_tvlv_len. Alternatively, perform this check in batadv_v_ogm_receive() before dispatching.
CVE pattern: Network packet length field not validated against actual buffer size before traversal

batadv_frag_insert_packet() — net/batman-adv/fragmentation.c FP confidence=high

The scanner flagged the use of a network-supplied seqno value as an array index, but the value is reduced by modulo BATADV_FRAG_BUFFER_COUNT before use. Since the array 'orig_node->fragments' has exactly BATADV_FRAG_BUFFER_COUNT elements, the modulo operation is a mathematically tight bounds guarantee. No counterexample exists: for any 16-bit seqno, seqno % BATADV_FRAG_BUFFER_COUNT is always in [0, BATADV_FRAG_BUFFER_COUNT-1]. The apparent 16→8 bit truncation is also safe because the modulo result fits in u8 regardless of input.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 162
Taint snippetbucket = seqno % BATADV_FRAG_BUFFER_COUNT;
Tainted varbucket
Truncationline 162: 16 → 8-bit u8
Sink snippetbucket = seqno % BATADV_FRAG_BUFFER_COUNT;
Possibly guardedno
Dismissed: seqno is network-supplied (u16), but 'seqno % BATADV_FRAG_BUFFER_COUNT' where BATADV_FRAG_BUFFER_COUNT=8 always yields a value in [0,7], well within u8 range. The truncation from 16-bit to 8-bit loses no information because the mathematical result is bounded. No counterexample can be constructed: any u16 modulo 8 is in [0,7].

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 161
Taint snippetseqno = ntohs(frag_packet->seqno);
Tainted varbucket
Subscript[] line 175
Sink snippetchain = &orig_node->fragments[bucket];
Possibly guardedno
Dismissed: The array subscript 'bucket' is computed as 'seqno % BATADV_FRAG_BUFFER_COUNT'. This modulo operation is a perfect bounds check for the 'fragments[BATADV_FRAG_BUFFER_COUNT]' array: the result is always in [0, BATADV_FRAG_BUFFER_COUNT-1]. Attempted counterexample: seqno=65535 gives 65535%8=7, still valid. No OOB is possible regardless of the network-supplied seqno value.

batadv_frag_merge_packets() — net/batman-adv/fragmentation.c FP confidence=medium

The taint from ntohs(packet->total_size) is genuinely server-supplied and controls the ntail argument to pskb_expand_head(). However, the memcpy operations flagged inside pskb_expand_head() are not controlled by the tainted ntail value: the first memcpy (line 2320) copies skb_tail_pointer(skb)-skb->head bytes (old buffer geometry, not tainted size), and the second (line 2322) writes to data+size where size has been adjusted by SKB_WITH_OVERHEAD() on the actually-allocated buffer — both are bounded by real allocation outcomes. If ntail is negative (total_size < skb_out->len), kmalloc_reserve will likely fail and pskb_expand_head returns -ENOMEM, which the caller handles. No concrete counterexample produces an OOB write through these flagged memcpy paths.

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

CategoryCat A — server offset → pointer → memory op
Taint sourcentohs() line 276
Taint snippetsize = ntohs(packet->total_size) + hdr_size;
Tainted varsize
Call siteline 279 — passes size to pskb_expand_head()
Call snippetif (pskb_expand_head(skb_out, 0, size - skb_out->len, GFP_ATOMIC) < 0) {
Sink (in callee)memcpy() line 2320 (arg 0, role=pointer)
Sink snippetmemcpy(data + nhead, skb->head, skb_tail_pointer(skb) - skb->head);
Possibly guardedno
Dismissed: The memcpy at skbuff.c:2320 copies 'skb_tail_pointer(skb) - skb->head' bytes — this is the existing SKB data length, not derived from the tainted ntail/size argument. The tainted value only affects how much tail space is allocated; the copy is bounded by the old buffer's actual used length. No OOB write is possible through this path from the tainted server value.

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

CategoryCat A — server offset → pointer → memory op
Taint sourcentohs() line 276
Taint snippetsize = ntohs(packet->total_size) + hdr_size;
Tainted varsize
Call siteline 279 — passes size to pskb_expand_head()
Call snippetif (pskb_expand_head(skb_out, 0, size - skb_out->len, GFP_ATOMIC) < 0) {
Sink (in callee)memcpy() line 2322 (arg 0, role=pointer)
Sink snippetmemcpy((struct skb_shared_info *)(data + size),
Possibly guardedno
Dismissed: The memcpy at skbuff.c:2322 writes the skb_shared_info to 'data + size' where size = SKB_WITH_OVERHEAD(actually_allocated_buffer_size). This pointer arithmetic is derived from the real allocation result (post-kmalloc_reserve adjustment via SKB_WITH_OVERHEAD), not directly from the raw tainted ntail value. The skb_shared_info is always placed at the end of the allocated buffer by design. No exploitable OOB condition arises from the tainted server-supplied total_size field through this path.

batadv_recv_mcast_packet() — net/batman-adv/routing.c FP confidence=high

batadv_recv_mcast_packet() validates tvlv_buff_len against actual SKB data length (line 1367) and alignment (line 1373) before passing it to batadv_tvlv_containers_process(). The callee itself performs per-element bounds checking within the loop (lines 520-521, 526-527), ensuring no out-of-bounds access can occur even with adversarial tvlv_hdr->len values within the TVLV buffer. The validation discipline here is sound at both levels.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1365
Taint snippettvlv_buff_len = ntohs(mcast_packet->tvlv_len);
Tainted vartvlv_buff_len
Call siteline 1376 — passes tvlv_buff_len to batadv_tvlv_containers_process()
Call snippetret = batadv_tvlv_containers_process(bat_priv, BATADV_MCAST, NULL, skb,
Loopwhile_loop line 514
Sink snippetwhile (tvlv_value_len >= sizeof(*tvlv_hdr)) {
Possibly guardedyes (heuristic)
Dismissed: Two-level validation is in place: (1) caller checks tvlv_buff_len <= skb->len - hdr_size before the call, bounding the region passed to the callee; (2) callee batadv_tvlv_containers_process() checks each inner tvlv_value_cont_len against remaining tvlv_value_len before advancing the pointer (lines 520-521) and also checks alignment (lines 526-527). No counterexample can be constructed that passes line 1367 yet causes OOB in the callee, because the callee's per-element checks prevent overrun within the already-bounded buffer.

batadv_recv_unicast_tvlv() — net/batman-adv/routing.c FP confidence=high

The function batadv_recv_unicast_tvlv() properly validates tvlv_buff_len against the actual skb payload before passing it to batadv_tvlv_containers_process(). The check at line 1121 ensures tvlv_buff_len <= skb->len - hdr_size, bounding it to actual received data. Inside batadv_tvlv_containers_process(), the while loop uses tvlv_value_len as an upper bound guard (not as a direct index), and every inner access is further bounded by per-element checks (tvlv_value_cont_len > tvlv_value_len). The loop cannot overread because it decrements tvlv_value_len at each step and checks before accessing. No counterexample can be constructed that passes both the outer check (line 1121) and causes OOB inside the callee.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1119
Taint snippettvlv_buff_len = ntohs(unicast_tvlv_packet->tvlv_len);
Tainted vartvlv_buff_len
Call siteline 1124 — passes tvlv_buff_len to batadv_tvlv_containers_process()
Call snippetret = batadv_tvlv_containers_process(bat_priv, BATADV_UNICAST_TVLV,
Loopwhile_loop line 514
Sink snippetwhile (tvlv_value_len >= sizeof(*tvlv_hdr)) {
Possibly guardedyes (heuristic)
Dismissed: The outer guard at line 1121 (tvlv_buff_len > skb->len - hdr_size → goto free_skb) ensures tvlv_buff_len is at most the actual bytes available in the skb beyond the header. Inside batadv_tvlv_containers_process(), tvlv_value_len (which receives tvlv_buff_len) is used only as a loop termination condition (line 514: while tvlv_value_len >= sizeof(*tvlv_hdr)), not as a direct memory offset or allocation size. Each iteration subtracts sizeof(*tvlv_hdr) and then tvlv_value_cont_len from tvlv_value_len after checking tvlv_value_cont_len <= tvlv_value_len (line 520). This double-check pattern prevents any overread. No counterexample exists: any tvlv_buff_len that passes the outer check is bounded to real buffer data, and the inner per-element checks prevent advancing beyond that bound.

batadv_send_other_tt_response() — net/batman-adv/translation-table.c FP confidence=high

The flagged function batadv_tt_global_check_crc() is itself a validation/checking function. Its purpose is to validate that the CRC data in the received tt_vlan array (num_vlan entries) matches locally stored state. The loop inside it (line 2824) iterates over the vlan entries, but each iteration accesses tt_vlan_tmp = tt_vlan + i, which is a pointer into the tt_data->vlan_data array. The concern would be whether num_vlan could cause out-of-bounds access on tt_vlan. However, this function IS the validator — it is called specifically to check the received data. The accesses inside it are exactly the validation logic. Furthermore, the function name 'batadv_tt_global_check_crc' and its structure (it returns false on mismatch, true on success) make it clear this is a validation function, not a consumer. The loop bound concern is about whether tt_vlan has at least num_vlan entries, but since tt_vlan points into a received tvlv buffer, callers upstream are responsible for validating the buffer size. The static analysis treats internal accesses of a validator as sinks, which is a false positive per the stated rules.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 3031
Taint snippet!batadv_tt_global_check_crc(req_dst_orig_node, tt_data->vlan_data,
Tainted varntohs(tt_data->num_vlan)
Call siteline 3031 — passes ntohs(tt_data->num_vlan) to batadv_tt_global_check_crc()
Call snippet!batadv_tt_global_check_crc(req_dst_orig_node, tt_data->vlan_data,
Loopfor_loop line 2824
Sink snippetfor (i = 0; i < num_vlan; i++) {
Possibly guardedno
Dismissed: batadv_tt_global_check_crc() is a validation function called specifically to validate the server-supplied tt_data. The loop inside it (iterating num_vlan times over tt_vlan) is the validation logic itself, not a dangerous sink. Per the analysis rules, accesses inside a validator function are part of validation logic and not vulnerable sinks. Additionally, the TVLV receive path in batman-adv typically validates the overall TVLV buffer length against the declared num_vlan before dispatching to this code path, though that validation occurs earlier in the receive chain. The finding is a false positive because the flagged sink is internal to the validator.

batadv_tvlv_container_ogm_append() — net/batman-adv/tvlv.c FP confidence=high

The tvlv container list is internally managed by the kernel (registered via batadv_tvlv_container_register with kernel-controlled lengths), not populated from received network packets. The buffer is pre-sized using batadv_tvlv_container_list_size() which iterates the same locked list summing the same ntohs(len) values, so the destination buffer is guaranteed to accommodate every memcpy. The spin_lock_bh held throughout prevents TOCTOU between sizing and copying.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 365
Taint snippetmemcpy(tvlv_value, tvlv + 1, ntohs(tvlv->tvlv_hdr.len));
Tainted varntohs(tvlv->tvlv_hdr.len)
Sinkmemcpy() line 365 (arg 2, role=size)
Sink snippetmemcpy(tvlv_value, tvlv + 1, ntohs(tvlv->tvlv_hdr.len));
Possibly guardedno
Dismissed: ntohs(tvlv->tvlv_hdr.len) is not server-supplied; it comes from locally-registered tvlv containers. The buffer is allocated with batadv_tvlv_realloc_packet_buff() to hold exactly batadv_tvlv_container_list_size() bytes, which is computed by summing sizeof(batadv_tvlv_hdr)+ntohs(len) for each container under the same spinlock. No counterexample exists: any value of len that would cause OOB in the memcpy would have caused batadv_tvlv_container_list_size() to allocate a correspondingly larger buffer. The spin_lock_bh ensures the list cannot change between sizing and copying.

batadv_tvlv_container_register() — net/batman-adv/tvlv.c FP confidence=high

The struct tvlv_new is locally allocated and initialized by this function. The field tvlv_new->tvlv_hdr.len is set on line 250 via htons(tvlv_value_len), then immediately read back via ntohs() on line 252. This is a local round-trip, not a server-supplied value. The allocation on line 244 allocates exactly sizeof(*tvlv_new)+tvlv_value_len bytes, so the memcpy destination is correctly sized. The source buffer validity is an API contract between kernel callers (not a network input path).

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 252
Taint snippetmemcpy(tvlv_new + 1, tvlv_value, ntohs(tvlv_new->tvlv_hdr.len));
Tainted varntohs(tvlv_new->tvlv_hdr.len)
Sinkmemcpy() line 252 (arg 2, role=size)
Sink snippetmemcpy(tvlv_new + 1, tvlv_value, ntohs(tvlv_new->tvlv_hdr.len));
Possibly guardedno
Dismissed: The scanner incorrectly identifies ntohs() as a server-supplied taint source. In this function, tvlv_new is a locally-allocated struct, and tvlv_new->tvlv_hdr.len is written on line 250 with htons(tvlv_value_len) before being read back on line 252. The round-tripped value equals tvlv_value_len. The kzalloc on line 244 allocates sizeof(*tvlv_new)+tvlv_value_len bytes, so the destination of the memcpy (tvlv_new+1) has exactly tvlv_value_len bytes, matching the copy length. No counterexample can be constructed: any value that passes the allocation would give a destination large enough for the copy.

batadv_tvlv_ogm_receive() — net/batman-adv/tvlv.c FP confidence=medium

The server-supplied tvlv_value_len controls iteration in batadv_tvlv_containers_process(), but that function IS the parsing/validation logic — its per-element checks (line 520: tvlv_value_cont_len > tvlv_value_len, line 526: alignment check) ensure the loop stays within the declared tvlv_value_len boundary. The real question of whether tvlv_value_len is validated against the actual skb length belongs at the receive layer above batadv_ogm_receive(), which is outside the scope of this finding. The callee is a validator, not a vulnerable sink.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 589
Taint snippettvlv_value_len = ntohs(batadv_ogm_packet->tvlv_len);
Tainted vartvlv_value_len
Call siteline 595 — passes tvlv_value_len to batadv_tvlv_containers_process()
Call snippetbatadv_tvlv_containers_process(bat_priv, BATADV_IV_OGM, orig_node, NULL,
Loopwhile_loop line 514
Sink snippetwhile (tvlv_value_len >= sizeof(*tvlv_hdr)) {
Possibly guardedno
Dismissed: batadv_tvlv_containers_process() is the parsing/validation function — its internal loop uses tvlv_value_len as the declared buffer bound and validates each per-element length against remaining tvlv_value_len before advancing (line 520). No counterexample can be constructed that passes the per-element guard while causing OOB within the declared boundary. Whether tvlv_value_len is validated against the actual skb data length is a concern in the outer receive path, not in this function. The scanner misidentifies the validator's internal loop as a vulnerable sink.

lowpan_control_write() — net/bluetooth/6lowpan.c FP confidence=high

The flagged 'buf_size' is computed entirely within the kernel as min(count, sizeof(buf) - 1), where sizeof(buf) is 32 (a compile-time constant). The result is therefore clamped to at most 31, which is strictly less than the 32-byte destination buffer. No user-supplied value is used as the size argument to copy_from_user without being bounded first. The scanner appears to have propagated taint from the user-supplied 'count' through the min() call and incorrectly concluded the result is unbounded.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 1121
Taint snippetif (copy_from_user(buf, user_buffer, buf_size))
Tainted varbuf_size
Unvalidated sizecopy_from_user() arg 2 line 1121 — size buf_size
Sink snippetif (copy_from_user(buf, user_buffer, buf_size))
Possibly guardedno
Dismissed: buf_size = min(count, sizeof(buf) - 1) = min(count, 31). The result is always <= 31 < 32 (sizeof(buf)), so copy_from_user can never overflow the 32-byte stack buffer. No counterexample can be constructed because min() provides an absolute upper bound of 31. This is a classic false positive from taint propagation through min() without recognising that the second operand is a compile-time constant less than the buffer size.

bnep_ctrl_set_mcfilter() — net/bluetooth/bnep/core.c FP confidence=high

The function validates len >= n (raw byte count) before dividing n by ETH_ALEN*2=12 to get the iteration count. Since n_iterations * 12 <= n_original <= len, the loop cannot read beyond the validated buffer. The bounds check at line 157 is sufficient when combined with the integer division at line 163.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourceget_unaligned_be16() line 153
Taint snippetn = get_unaligned_be16(data);
Tainted varn
Loopfor_loop line 174
Sink snippetfor (; n > 0; n--) {
Possibly guardedyes (heuristic)
Dismissed: The pre-loop check `if (len < n) return -EILSEQ` ensures the raw byte count n fits in the buffer. After `n /= (ETH_ALEN * 2)`, the loop runs n_new = n_original/12 times, each consuming 12 bytes, for a total of n_new*12 <= n_original <= len bytes. No counterexample can be constructed: any values passing the guard satisfy n_iterations*12 <= len. The scanner flagged this as 'possibly guarded' and the guard is in fact sufficient.

bnep_ctrl_set_netfilter() — net/bluetooth/bnep/core.c FP confidence=high

The function performs correct two-level validation: (1) packet buffer bounds checked at line 111 before the loop (original n bytes available), (2) array bounds checked at line 118 (n/4 entries <= BNEP_MAX_PROTO_FILTERS). The loop reads exactly (n/4)*4 bytes which is <= original n bytes validated against len. No counterexample is constructable.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourceget_unaligned_be16() line 107
Taint snippetn = get_unaligned_be16(data);
Tainted varn
Loopfor_loop line 122
Sink snippetfor (i = 0; i < n; i++) {
Possibly guardedyes (heuristic)
Dismissed: Two guards protect the loop: (a) line 111 checks len >= n (original byte count), ensuring the packet buffer has enough data for the loop to read (n/4)*4 <= n bytes; (b) line 118 checks n/4 <= BNEP_MAX_PROTO_FILTERS, bounding array index. No counterexample can be constructed that passes both guards yet causes OOB. False positive.

hci_get_conn_list() — net/bluetooth/hci_conn.c FP confidence=high

The 'size' variable used in copy_to_user() is not user-controlled at the point of the call. Although req.conn_num is read from user space, it is validated at line 2773 (must be non-zero and ≤ (PAGE_SIZE*2)/sizeof(*ci)). The allocation at line 2778 uses sizeof(req) + req.conn_num * sizeof(*ci), which is safe given that bound. At line 2805, size is RECOMPUTED as sizeof(req) + n * sizeof(*ci), where n is the kernel-internal counter of actual connections found (capped at req.conn_num by the break at line 2798). So n ≤ req.conn_num, and the new size ≤ the originally allocated size. The buffer 'cl' has capacity for the original (larger) size, so copying the smaller recomputed size is strictly within the allocated region. The copy_to_user destination 'arg' is a user pointer; the kernel copies at most as much as the user asked for (bounded by the validated req.conn_num), so there is no overflow of the user buffer beyond what the user explicitly declared it can hold.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 2809
Taint snippeterr = copy_to_user(arg, cl, size);
Tainted varsize
Unvalidated sizecopy_to_user() arg 2 line 2809 — size size
Sink snippeterr = copy_to_user(arg, cl, size);
Possibly guardedno
Dismissed: The user-supplied req.conn_num is validated at line 2773 against (PAGE_SIZE*2)/sizeof(*ci). The 'size' passed to copy_to_user is sizeof(req)+n*sizeof(*ci) where n≤req.conn_num, so no counterexample exists: any value of req.conn_num that passes the guard produces a size that both fits in the allocation and is within the user's declared buffer. False positive.

force_no_mitm_write() — net/bluetooth/hci_debugfs.c FP confidence=high

The scanner misidentifies the taint source. buf_size is computed as min(count, sizeof(buf)-1) where sizeof(buf) is 32 (compile-time constant). The count parameter is user-supplied (from the VFS write syscall), but buf_size is immediately clamped to at most 31 via the min() call before copy_from_user is invoked. This is the standard safe pattern for debugfs write handlers. The scanner erroneously traces buf_size as tainted from copy_from_user's return value, but buf_size is actually computed BEFORE copy_from_user is called and is bounded by the stack buffer size.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 1168
Taint snippetif (copy_from_user(buf, user_buf, buf_size))
Tainted varbuf_size
Unvalidated sizecopy_from_user() arg 2 line 1168 — size buf_size
Sink snippetif (copy_from_user(buf, user_buf, buf_size))
Possibly guardedno
Dismissed: buf_size = min(count, sizeof(buf) - 1) = min(count, 31). This clamps the copy size to at most 31 bytes, well within the 32-byte stack buffer. No counterexample is possible: any value of count (including SIZE_MAX) results in buf_size <= 31, and buf[buf_size] = '\0' writes at most to index 31, which is within bounds. The scanner appears to have confused the output of copy_from_user (the taint introduced into 'buf') with the size argument 'buf_size', which is pre-computed and bounded before the call.

hci_le_per_adv_report_evt() — net/bluetooth/hci_event.c FP confidence=high

The scanner incorrectly propagates taint from le16_to_cpu(ev->sync_handle) through hci_conn_hash_lookup_pa_sync_handle() to its return value pa_sync. The sync_handle field is used only as a lookup key into the kernel's internal hci_conn hash table. The returned pa_sync pointer is a kernel-allocated, kernel-managed struct hci_conn object — not a pointer derived from the server-supplied handle value. The null check at line 6620 further ensures safety. All field accesses in mgmt_device_connected() operate on legitimate kernel data structures, not attacker-controlled memory.

Finding #1 — Category E — cross-function via mgmt_device_connected() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6616
Taint snippetpa_sync = hci_conn_hash_lookup_pa_sync_handle
Tainted varpa_sync
Call siteline 6629 — passes pa_sync to mgmt_device_connected()
Call snippetmgmt_device_connected(hdev, pa_sync, NULL, 0);
Pointer derefpa_sync-> line 9897
Sink snippetbacpy(&ev->addr.bdaddr, &conn->dst);
Possibly guardedno
Dismissed: pa_sync is returned by hci_conn_hash_lookup_pa_sync_handle() — a hash table lookup using sync_handle as a key. The returned pointer is a kernel-managed struct hci_conn, not a pointer derived from the server-supplied handle value. The null check guards against no-match case. bacpy() on conn->dst accesses a legitimate kernel struct field.

Finding #2 — Category E — cross-function via mgmt_device_connected() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6616
Taint snippetpa_sync = hci_conn_hash_lookup_pa_sync_handle
Tainted varpa_sync
Call siteline 6629 — passes pa_sync to mgmt_device_connected()
Call snippetmgmt_device_connected(hdev, pa_sync, NULL, 0);
Pointer derefpa_sync-> line 9898
Sink snippetev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Possibly guardedno
Dismissed: Same false taint propagation through hash lookup. conn->type and conn->dst_type are fields of a kernel-allocated struct hci_conn, not attacker-controlled.

Finding #3 — Category E — cross-function via mgmt_device_connected() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6616
Taint snippetpa_sync = hci_conn_hash_lookup_pa_sync_handle
Tainted varpa_sync
Call siteline 6629 — passes pa_sync to mgmt_device_connected()
Call snippetmgmt_device_connected(hdev, pa_sync, NULL, 0);
Pointer derefpa_sync-> line 9903
Sink snippetev->flags = __cpu_to_le32(flags);
Possibly guardedno
Dismissed: Same false taint propagation. ev->flags is written with a locally-computed flags variable, not with any server-supplied data. The sink is writing TO ev (local skb data), not reading from conn in a dangerous way.

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

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 6616
Taint snippetpa_sync = hci_conn_hash_lookup_pa_sync_handle
Tainted varpa_sync
Call siteline 6629 — passes pa_sync to mgmt_device_connected()
Call snippetmgmt_device_connected(hdev, pa_sync, NULL, 0);
Sink (in callee)memcmp() line 9916 (arg 2, role=size)
Sink snippetif (memcmp(conn->dev_class, "\0\0\0", sizeof(conn->dev_class)))
Possibly guardedyes (heuristic)
Dismissed: memcmp() size argument is sizeof(conn->dev_class) — a compile-time constant, not any server-supplied value. The scanner misidentified the taint role. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 6616
Taint snippetpa_sync = hci_conn_hash_lookup_pa_sync_handle
Tainted varpa_sync
Call siteline 6629 — passes pa_sync to mgmt_device_connected()
Call snippetmgmt_device_connected(hdev, pa_sync, NULL, 0);
Pointer derefpa_sync-> line 9921
Sink snippetev->eir_len = cpu_to_le16(eir_len);
Possibly guardedno
Dismissed: ev->eir_len is written with locally-computed eir_len, not any server-supplied data. The conn pointer is a kernel-managed struct hci_conn from the hash table lookup, not a server-supplied pointer.

hci_sock_sendmsg() — net/bluetooth/hci_sock.c FP confidence=high

The function properly validates user-supplied data before dangerous operations. The ogf array subscript is protected by C short-circuit evaluation: the array access only occurs in the right-hand side of a || expression, which is only evaluated when ogf <= HCI_SFLT_MAX_OGF, making the array access always in-bounds. The static scanner apparently did not model C's short-circuit evaluation semantics correctly.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 1879
Taint snippetu16 opcode = get_unaligned_le16(skb->data);
Tainted varogf
Subscript[] line 1885
Sink snippet&hci_sec_filter.ocf_mask[ogf])) &&
Possibly guardedyes (heuristic)
Dismissed: C's short-circuit OR evaluation ensures hci_sec_filter.ocf_mask[ogf] is only accessed when (ogf > HCI_SFLT_MAX_OGF) is false, i.e., when ogf <= HCI_SFLT_MAX_OGF. Since the array is sized for HCI_SFLT_MAX_OGF+1 elements, no OOB access is possible. No counterexample can be constructed — any ogf > HCI_SFLT_MAX_OGF causes the || short-circuit to skip the array access, and any ogf <= HCI_SFLT_MAX_OGF is a valid index. The scanner did not model short-circuit evaluation, producing a false positive.

send_hci_cmd_sync() — net/bluetooth/mgmt.c FP confidence=high

The taint tracker incorrectly propagates taint from cp->opcode (passed as input to __hci_cmd_sync_ev()) through to the function's return value skb. The returned sk_buff is a kernel-allocated buffer whose pointer is not derived from cp->opcode. Even if taint were legitimate: (1) mgmt_status() validates its argument with ARRAY_SIZE bounds before indexing; (2) mgmt_cmd_complete() allocates the destination buffer with rp_len included in the allocation size before memcpy, making it safe by construction; (3) the struct field writes in mgmt_cmd_complete() (hdr->, ev->) are to locally-allocated buffers, not indexed by any tainted value.

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

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2644 — passes skb to mgmt_status()
Call snippetmgmt_status(PTR_ERR(skb)));
Subscript (in callee)[] line 315
Sink snippetreturn mgmt_status_table[err];
Possibly guardedyes (heuristic)
Dismissed: skb is the return value of __hci_cmd_sync_ev(), not derived from cp->opcode. PTR_ERR(skb) yields a small negative errno. mgmt_status() checks err<0 (routes to mgmt_errno_status) and err<ARRAY_SIZE(mgmt_status_table) before indexing — no counterexample possible. False positive.

Finding #2 — Category E — cross-function via mgmt_cmd_complete() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2648 — passes skb to mgmt_cmd_complete()
Call snippetmgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
Pointer derefskb-> line 182
Sink snippethdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Possibly guardedno
Dismissed: Taint incorrectly propagated from cp->opcode through __hci_cmd_sync_ev() return value to skb. hdr is allocated locally in mgmt_cmd_complete() via alloc_skb/skb_put — writing to hdr->opcode is not a tainted dereference. False positive from taint tracker misattribution.

Finding #3 — Category E — cross-function via mgmt_cmd_complete() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2648 — passes skb to mgmt_cmd_complete()
Call snippetmgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
Pointer derefskb-> line 183
Sink snippethdr->index = cpu_to_le16(index);
Possibly guardedno
Dismissed: Same false taint propagation as #2. hdr->index write targets a locally allocated buffer unrelated to skb content or cp->opcode value. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2648 — passes skb to mgmt_cmd_complete()
Call snippetmgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
Pointer derefskb-> line 184
Sink snippethdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Possibly guardedno
Dismissed: Same false taint propagation. hdr->len write uses sizeof(*ev)+rp_len where rp_len=skb->len is used consistently in alloc_skb and skb_put. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2648 — passes skb to mgmt_cmd_complete()
Call snippetmgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
Pointer derefskb-> line 187
Sink snippetev->opcode = cpu_to_le16(cmd);
Possibly guardedno
Dismissed: Same false taint propagation. ev->opcode write targets locally allocated struct. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2648 — passes skb to mgmt_cmd_complete()
Call snippetmgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
Pointer derefskb-> line 188
Sink snippetev->status = status;
Possibly guardedno
Dismissed: Same false taint propagation. ev->status write targets locally allocated struct. False positive.

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

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2648 — passes skb to mgmt_cmd_complete()
Call snippetmgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
Sink (in callee)memcpy() line 191 (arg 2, role=size)
Sink snippetmemcpy(ev->data, rp, rp_len);
Possibly guardedno
Dismissed: rp_len=skb->len is used as memcpy size, but the destination buffer was allocated as alloc_skb(sizeof(*hdr)+sizeof(*ev)+rp_len) — the allocation already accounts for rp_len bytes. No counterexample possible for OOB. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2648 — passes skb to mgmt_cmd_complete()
Call snippetmgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
Pointer derefskb-> line 191
Sink snippetmemcpy(ev->data, rp, rp_len);
Possibly guardedno
Dismissed: ev->data is the destination of memcpy, allocated with sufficient size as noted in #7. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2648 — passes skb to mgmt_cmd_complete()
Call snippetmgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
Pointer derefskb-> line 193
Sink snippetmskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
Possibly guardedno
Dismissed: hdr->index dereference targets locally allocated hdr struct. Taint incorrectly propagated. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 2637
Taint snippetskb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cp->opcode),
Tainted varskb
Call siteline 2648 — passes skb to mgmt_cmd_complete()
Call snippetmgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_HCI_CMD_SYNC, 0,
Pointer derefskb-> line 197
Sink snippetskb->tstamp = mskb->tstamp;
Possibly guardedno
Dismissed: skb->tstamp at line 197 refers to the locally allocated skb in mgmt_cmd_complete(), not the skb from __hci_cmd_sync_ev(). The taint tracker has completely lost track of which skb is which. False positive.

bpf_ctx_finish() — net/bpf/test_run.c FP confidence=high

The copy_size variable in bpf_ctx_finish() is NOT user-controlled in a dangerous way. It is computed as min(size, kattr->test.ctx_size_out) where 'size' is the kernel-internal size of the context structure passed by the caller (e.g., sizeof(struct xdp_md), sizeof(struct bpf_flow_keys), sizeof(*user_ctx)) — a compile-time constant. The 'data' buffer pointed to by the 'data' parameter holds exactly 'size' bytes. The copy_size is then clamped at line 896-899 to kattr->test.ctx_size_out (the user-supplied output buffer size). Since copy_size <= size (the actual data buffer size) and copy_size <= kattr->test.ctx_size_out (the user output buffer size), both source and destination are correctly bounded. The scanner flagged copy_size as tainted because kattr->test.ctx_size_out is user-supplied, but the clamping logic at line 896-899 ensures copy_size never exceeds either buffer. No counterexample can be constructed that passes the guard (copy_size = min(size, ctx_size_out) <= size = actual data length) and causes OOB.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 901
Taint snippetif (copy_to_user(data_out, data, copy_size))
Tainted varcopy_size
Unvalidated sizecopy_to_user() arg 2 line 901 — size copy_size
Sink snippetif (copy_to_user(data_out, data, copy_size))
Possibly guardedno
Dismissed: copy_size starts as 'size' (kernel-internal, caller-supplied compile-time sizeof), then is clamped to min(size, kattr->test.ctx_size_out) at lines 896-899. This means copy_size <= size (so no read past the 'data' buffer) and copy_size <= ctx_size_out (so no write past the user output buffer). No counterexample exists: any value of ctx_size_out either leaves copy_size == size (no truncation) or reduces it further. The false positive arises because the taint analysis tracks ctx_size_out as user-controlled and propagates it into copy_size without recognizing the min() clamping semantics.

bpf_ctx_init() — net/bpf/test_run.c FP confidence=high

The tainted variable 'size' (kattr->test.ctx_size_in) is user-supplied, but it is explicitly bounded by max_size via min_t(u32, max_size, size) at line 876 before being passed to copy_from_user(). The destination buffer 'data' was allocated with kzalloc(max_size) at line 865. Therefore the copy length is at most max_size, which is exactly the buffer size. Additionally, bpf_check_uarg_tail_zero() is called first to validate that any bytes in data_in beyond min(max_size, size) are zero, providing additional safety. The scanner missed the min_t() clamping at line 876 which is the definitive bound enforcement.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 877
Taint snippetif (copy_from_user(data, data_in, size)) {
Tainted varsize
Unvalidated sizecopy_from_user() arg 2 line 877 — size size
Sink snippetif (copy_from_user(data, data_in, size)) {
Possibly guardedno
Dismissed: The user-supplied 'size' (ctx_size_in) is clamped at line 876 via 'size = min_t(u32, max_size, size)' before use in copy_from_user(). The destination buffer is kzalloc(max_size), so the copy length after clamping is at most max_size bytes — exactly the buffer capacity. No counterexample exists: any value of size, whether 0, max_size, or UINT_MAX, results in a copy of at most max_size bytes into a max_size-byte buffer. This is a false positive.

bpf_prog_test_run_skb() — net/bpf/test_run.c FP confidence=high

The function carefully bounds data_len to PAGE_SIZE via min_t() before using it as the size argument to copy_from_user(), and the destination buffer is always a single page (PAGE_SIZE bytes) allocated by alloc_page(). The validation is sufficient and no OOB is possible.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 1149
Taint snippetif (copy_from_user(page_address(page), data_in + copied,
Tainted vardata_len
Unvalidated sizecopy_from_user() arg 2 line 1149 — size data_len
Sink snippetif (copy_from_user(page_address(page), data_in + copied,
Possibly guardedno
Dismissed: data_len is computed as min_t(u32, kattr->test.data_size_in - copied, PAGE_SIZE), which clamps it to at most PAGE_SIZE. The destination buffer is page_address(page) where page is allocated by alloc_page(GFP_KERNEL), which always provides exactly PAGE_SIZE bytes. No counterexample can be constructed because data_len <= PAGE_SIZE == destination size. The scanner incorrectly flagged user-origin taint without recognizing the min_t() clamp; this is a false positive.

bpf_prog_test_run_xdp() — net/bpf/test_run.c FP confidence=high

The function reads user-supplied kattr->test.data_size_in, but data_len is bounded by min_t(u32, ..., PAGE_SIZE) before being used as the copy_from_user size argument. The destination page is always PAGE_SIZE bytes (alloc_page), so the copy is safe. The scanner incorrectly propagated user-taint through the min_t clamp without recognizing it as a sufficient bound.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 1448
Taint snippetif (copy_from_user(page_address(page), data_in + size,
Tainted vardata_len
Unvalidated sizecopy_from_user() arg 2 line 1448 — size data_len
Sink snippetif (copy_from_user(page_address(page), data_in + size,
Possibly guardedno
Dismissed: data_len = min_t(u32, kattr->test.data_size_in - size, PAGE_SIZE) ensures data_len <= PAGE_SIZE. The destination is alloc_page() which provides exactly PAGE_SIZE bytes. No counterexample can be constructed where data_len > PAGE_SIZE, so the copy cannot overflow. This is a false positive caused by the taint analysis propagating user-supplied taint through a min_t clamp that effectively sanitizes the value.

bpf_test_finish() — net/bpf/test_run.c FP confidence=high

Both findings are false positives. The tainted values 'len' and 'data_len' are NOT user-supplied sizes — they are kernel-internal computations bounded by min() operations against kernel-controlled values. 'len' is min(copy_size, head_len) where copy_size is bounded by kattr->test.data_size_out (user-supplied but only used as a clamp, not as a direct copy size) and head_len = size - frag_size (kernel-computed from skb metadata). 'data_len' is min_t(u32, copy_size - offset, skb_frag_size(frag)) where both arguments are bounded: copy_size - offset is bounded by copy_size (which is itself bounded by the user's data_size_out or the kernel's size parameter), and skb_frag_size(frag) is the actual fragment size. The destination buffer is user-space (data_out) which is a user pointer, so copy_to_user is the correct mechanism. The copy sizes are strictly bounded by the minimum of the user's declared output buffer size and the actual data available. No OOB write to a kernel buffer is possible.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 458
Taint snippetif (copy_to_user(data_out, data, len))
Tainted varlen
Unvalidated sizecopy_to_user() arg 2 line 458 — size len
Sink snippetif (copy_to_user(data_out, data, len))
Possibly guardedno
Dismissed: len = min(copy_size, head_len). copy_size is either the original kernel-computed 'size' parameter or clamped to kattr->test.data_size_out (the user's declared output buffer size). head_len = size - frag_size is kernel-computed from skb metadata. The min() ensures len never exceeds either the actual data available or the user's declared buffer capacity. copy_to_user writes to user-space (data_out), which is the correct target — no kernel buffer overflow is possible. Counterexample attempt: even if data_size_out is very large, copy_size is clamped to size (the actual data length), so len <= size = head_len + frag_size, and since len = min(copy_size, head_len) <= head_len, the copy only covers the linear portion of the skb. No counterexample found.

Finding #2 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 476
Taint snippetif (copy_to_user(data_out + offset,
Tainted vardata_len
Unvalidated sizecopy_to_user() arg 2 line 476 — size data_len
Sink snippetif (copy_to_user(data_out + offset,
Possibly guardedno
Dismissed: data_len = min_t(u32, copy_size - offset, skb_frag_size(frag)). The loop guards ensure offset < copy_size before computing data_len, so copy_size - offset > 0. skb_frag_size(frag) is the kernel-managed actual fragment size. The min_t ensures data_len does not exceed either the remaining output buffer space or the actual fragment data. Additionally, after each iteration offset += data_len, maintaining the invariant that offset <= copy_size. copy_to_user writes to user-space at data_out + offset, which is within the user's declared output region. No kernel buffer is written. Counterexample attempt: for data_len to overflow, one would need copy_size - offset or skb_frag_size to be adversarially large, but both are bounded by kernel-internal values (copy_size is bounded by the actual data size, and skb_frag_size reflects real fragment sizes). No counterexample found.

br_ioctl_stub() — net/bridge/br_ioctl.c FP confidence=high

The scanner has misidentified IFNAMSIZ as a user-controlled taint source. IFNAMSIZ is a compile-time kernel constant (16), not derived from user input. The copy_from_user() call uses a fixed-size stack buffer 'buf[IFNAMSIZ]' as the destination and IFNAMSIZ as the copy length — both are kernel-internal constants. This is a standard safe pattern for copying a fixed-size interface name from userspace.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 435
Taint snippetif (copy_from_user(buf, uarg, IFNAMSIZ)) {
Tainted varIFNAMSIZ
Unvalidated sizecopy_from_user() arg 2 line 435 — size IFNAMSIZ
Sink snippetif (copy_from_user(buf, uarg, IFNAMSIZ)) {
Possibly guardedno
Dismissed: IFNAMSIZ is a compile-time constant (defined as 16 in the kernel headers), not derived from user input in any way. The taint source label 'copy_from_user() line 435' is the call itself, but the scanner has confused the constant size argument IFNAMSIZ with a tainted value. The destination buffer 'buf' is declared as 'char buf[IFNAMSIZ]' on the stack, and the copy length is exactly IFNAMSIZ — perfectly matched. Additionally, buf[IFNAMSIZ-1] = 0 ensures null-termination after the copy. No counterexample can be constructed because there is no variable involved in the size argument. This is a classic false positive from a taint analysis tool that incorrectly propagates taint through copy_from_user() to the constant size argument.

old_deviceless() — net/bridge/br_ioctl.c FP confidence=high

The scanner flagged IFNAMSIZ as a user-controlled size, but IFNAMSIZ is a kernel compile-time constant (16), not a value read from user space. The size argument to copy_from_user() is completely internal and not tainted by user data. The destination buffer 'buf' is declared as char buf[IFNAMSIZ], so the copy is exactly safe: IFNAMSIZ bytes copied into an IFNAMSIZ-byte stack buffer. This is a classic false positive from a taint analysis tool that incorrectly propagated taint through the macro/constant rather than recognizing it as a kernel-internal constant.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 382
Taint snippetif (copy_from_user(buf, argp, IFNAMSIZ))
Tainted varIFNAMSIZ
Unvalidated sizecopy_from_user() arg 2 line 382 — size IFNAMSIZ
Sink snippetif (copy_from_user(buf, argp, IFNAMSIZ))
Possibly guardedno
Dismissed: IFNAMSIZ is a kernel compile-time constant (#define IFNAMSIZ 16), not a user-supplied value. The taint analysis tool incorrectly labeled it as user-controlled. The destination buffer 'buf' is char buf[IFNAMSIZ] on the stack, and the copy uses exactly IFNAMSIZ as the length, so there is no overflow. No counterexample can be constructed because the size is not variable. This is a false positive.

br_ip4_multicast_igmp3_report() — net/bridge/br_multicast.c FP confidence=high

The function uses per-iteration ip_mc_may_pull() bounds checks that validate the cumulative 'len' before each access. Finding #1 is protected by per-iteration checks (form b). Findings #2-7 involve grec reloaded at line 2921 to a position already validated by both pull checks. Finding #8 involves nsrcs passed to a callee where the source array srcs was already bounds-checked to contain nsrcs*4 bytes. No genuine vulnerabilities exist.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 2861
Taint snippetnum = ntohs(ih->ngrec);
Tainted varnum
Loopfor_loop line 2864
Sink snippetfor (i = 0; i < num; i++) {
Possibly guardedno
Dismissed: Per-iteration bounds checks via ip_mc_may_pull() at lines 2866-2867 and 2875-2876 terminate the loop early if 'num' is too large for the packet. No counterexample possible: any iteration beyond packet bounds returns -EINVAL.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 2872
Taint snippetnsrcs = ntohs(grec->grec_nsrcs);
Tainted vargrec
Pointer derefgrec->grec_src line 2926
Sink snippetgrec->grec_src,
Possibly guardedno
Dismissed: grec is reloaded at line 2921 to skb->data + (len - sizeof(*grec) - nsrcs*4). At this point len was validated by ip_mc_may_pull to include sizeof(*grec) + nsrcs*4 bytes, so grec->grec_src (immediately after grec in memory) is within the validated region.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 2872
Taint snippetnsrcs = ntohs(grec->grec_nsrcs);
Tainted vargrec
Pointer derefgrec->grec_src line 2931
Sink snippetgrec->grec_src,
Possibly guardedno
Dismissed: Same as finding #2. The grec->grec_src access at line 2931 is covered by the same ip_mc_may_pull validation establishing that nsrcs*4 bytes after grec are accessible.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 2872
Taint snippetnsrcs = ntohs(grec->grec_nsrcs);
Tainted vargrec
Pointer derefgrec->grec_src line 2936
Sink snippetgrec->grec_src,
Possibly guardedno
Dismissed: Same as findings #2-3. grecn->grec_src at line 2936 is within the already-validated packet window.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 2872
Taint snippetnsrcs = ntohs(grec->grec_nsrcs);
Tainted vargrec
Pointer derefgrec->grec_src line 2941
Sink snippetgrec->grec_src,
Possibly guardedno
Dismissed: Same reasoning. grec->grec_src at line 2941 is safe.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 2872
Taint snippetnsrcs = ntohs(grec->grec_nsrcs);
Tainted vargrec
Pointer derefgrec->grec_src line 2946
Sink snippetgrec->grec_src,
Possibly guardedno
Dismissed: Same reasoning. grec->grec_src at line 2946 is safe.

Finding #7 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 2872
Taint snippetnsrcs = ntohs(grec->grec_nsrcs);
Tainted vargrec
Pointer derefgrec->grec_src line 2951
Sink snippetgrec->grec_src,
Possibly guardedno
Dismissed: Same reasoning. grec->grec_src at line 2951 is safe.

Finding #8 — Category F — cross-function via br_multicast_isinc_allow() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 2872
Taint snippetnsrcs = ntohs(grec->grec_nsrcs);
Tainted varnsrcs
Call siteline 2925 — passes nsrcs to br_multicast_isinc_allow()
Call snippetchanged = br_multicast_isinc_allow(brmctx, pg, h_addr,
Loopfor_loop line 2331
Sink snippetfor (src_idx = 0; src_idx < nsrcs; src_idx++) {
Possibly guardedyes (heuristic)
Dismissed: nsrcs is passed to br_multicast_isinc_allow along with grec->grec_src as the source array. The ip_mc_may_pull check at line 2875-2876 already validated that nsrcs*4 bytes are accessible starting at grec->grec_src. The callee loop accesses exactly src_idx*addr_size offsets within this validated range. No counterexample possible.

br_ip6_multicast_mld2_report() — net/bridge/br_multicast.c FP confidence=high

The function has robust per-iteration bounds checking. For finding #1, the loop always terminates on malformed packets via -EINVAL from ipv6_mc_may_pull() or the nsrcs_offset check, making the unvalidated 'num' safe. For finding #2, nsrcs is used in struct_size(grec, grec_src, nsrcs) + ipv6_mc_may_pull() BEFORE the grec pointer is formed and before nsrcs is passed to isinc_allow, establishing exactly the bounds that the callee's loop uses. The caller also runs ipv6_mc_check_mld() as a pre-validation gate.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 2987
Taint snippetnum = ntohs(mld2r->mld2r_ngrec);
Tainted varnum
Loopfor_loop line 2990
Sink snippetfor (i = 0; i < num; i++) {
Possibly guardedno
Dismissed: The loop body contains per-iteration bounds checks: (1) lines 2996-2998 check nsrcs_offset+sizeof(__nsrcs) against packet length, (2) line 3008-3009 calls ipv6_mc_may_pull(skb, len+grec_len) which returns -EINVAL if data is unavailable. Since len grows by grec_len each iteration, if num is larger than actual record count, the loop exits early with -EINVAL. No counterexample can pass both guards with a truncated packet. False positive.

Finding #2 — Category F — cross-function via br_multicast_isinc_allow() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 3005
Taint snippetnsrcs = ntohs(*_nsrcs);
Tainted varnsrcs
Call siteline 3061 — passes nsrcs to br_multicast_isinc_allow()
Call snippetchanged = br_multicast_isinc_allow(brmctx, pg, h_addr,
Loopfor_loop line 2331
Sink snippetfor (src_idx = 0; src_idx < nsrcs; src_idx++) {
Possibly guardedyes (heuristic)
Dismissed: Before passing nsrcs to br_multicast_isinc_allow(), the code at line 3006-3009 computes grec_len = struct_size(grec, grec_src, nsrcs) and calls ipv6_mc_may_pull(skb, len + grec_len), which validates that nsrcs source entries (each sizeof(struct in6_addr)) fit in the skb. The callee's loop accesses srcs + (src_idx * addr_size) for src_idx < nsrcs — identical arithmetic. No counterexample exists: any nsrcs that passes ipv6_mc_may_pull already guarantees the array is in-bounds. False positive.

ebt_vlan_mt() — net/bridge/netfilter/ebt_vlan.c FP confidence=high

The function parses a VLAN TCI field from a network packet. The 'prio' field is derived by right-shifting TCI by 13 bits and masking with 0x7, yielding a value in [0,7], which trivially fits in an unsigned char. The scanner's own note specifies this pattern as a false positive. No bounds issue exists.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 60
Taint snippetprio = (TCI >> 13) & 0x7;
Tainted varprio
Truncationline 60: 16 → 8-bit u8
Sink snippetprio = (TCI >> 13) & 0x7;
Possibly guardedno
Dismissed: The expression '(TCI >> 13) & 0x7' limits the result to the range [0,7] regardless of the 16-bit TCI value. No counterexample exists: any possible TCI input produces a value that fits in unsigned char. The truncation is safe because the masking occurs on the RHS before assignment. This matches the scanner's own false-positive exception rule.

compat_do_replace() — net/bridge/netfilter/ebtables.c FP confidence=high

The function copies user-supplied tmp.entries_size from userspace and uses it both as the vmalloc() allocation size and the copy_from_user() size argument. Since both use the same value, the copy cannot overflow the allocated buffer. The vmalloc() failure path is checked before the copy. While tmp.entries_size is user-controlled and unvalidated for lower/upper bounds as a semantic matter, there is no memory safety vulnerability: the allocation and copy are paired. The finding is a false positive for OOB write.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 2323
Taint snippetif (copy_from_user(
Tainted vartmp.entries_size
Unvalidated sizecopy_from_user() arg 2 line 2323 — size tmp.entries_size
Sink snippetif (copy_from_user(
Possibly guardedno
Dismissed: tmp.entries_size is user-controlled, but vmalloc(tmp.entries_size) is called first and its result is checked for NULL before copy_from_user uses the same size. The copy destination buffer is exactly sized to tmp.entries_size, so no OOB write is possible. Counterexample search: any value of tmp.entries_size that passes vmalloc (non-zero, not too large to allocate) will result in a correctly sized buffer — no concrete counterexample found. False positive.

compat_match_to_user() — net/bridge/netfilter/ebtables.c FP confidence=high

The flagged value 'strlen(match->name) + 1' is not user-supplied or server-supplied data. 'match' is a 'struct xt_match *' obtained from the kernel's internal match registry (m->u.match), where 'name' is a kernel-defined constant string embedded in the registered match descriptor. The destination buffer 'cm->u.name' is a fixed-size field (XT_EXTENSION_MAXNAMELEN / 29 bytes) in the user-space struct, and match names in the kernel are constrained to that same maximum length by the netfilter registration infrastructure. The size argument to copy_to_user() is therefore kernel-internally controlled and bounded, not server- or user-supplied.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 1659
Taint snippetif (copy_to_user(cm->u.name, match->name, strlen(match->name) + 1) ||
Tainted varstrlen(match->name) + 1
Unvalidated sizecopy_to_user() arg 2 line 1659 — size strlen(match->name) + 1
Sink snippetif (copy_to_user(cm->u.name, match->name, strlen(match->name) + 1) ||
Possibly guardedno
Dismissed: The taint source is misidentified: copy_to_user() is flagged as a taint source because it is used in a conditional, but the size argument 'strlen(match->name) + 1' derives from 'match->name', which is a kernel-registered constant string in struct xt_match, not user- or network-supplied data. All registered match names must fit within XT_EXTENSION_MAXNAMELEN (typically 29 bytes) as enforced by xt_register_match(). The destination cm->u.name has the same fixed-size bound. No counterexample can be constructed because the name length is bounded at registration time by the kernel itself. This is a false positive.

compat_target_to_user() — net/bridge/netfilter/ebtables.c FP confidence=high

The flagged copy_to_user() copies target->name, where 'target' is a struct xt_target — a kernel-internal object registered via xt_register_target(). The 'name' field is a fixed-size char array (XT_EXTENSION_MAXNAMELEN = 29 bytes) filled at module registration time with a string literal or compile-time constant. It is not server-supplied or user-controlled. The destination cm->u.name is also a fixed-size field of the same size in compat_ebt_entry_mwt. The scanner is confused because the taint source is misidentified — strlen(target->name)+1 is computed from a kernel-internal string, not from any network packet or user-supplied data.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 1691
Taint snippetif (copy_to_user(cm->u.name, target->name, strlen(target->name) + 1) ||
Tainted varstrlen(target->name) + 1
Unvalidated sizecopy_to_user() arg 2 line 1691 — size strlen(target->name) + 1
Sink snippetif (copy_to_user(cm->u.name, target->name, strlen(target->name) + 1) ||
Possibly guardedno
Dismissed: target->name is a kernel-internal field in struct xt_target, populated at module registration with a compile-time string constant (XT_EXTENSION_MAXNAMELEN bytes max). It is not server-supplied or user-controlled. The copy_to_user() destination cm->u.name is a fixed-size array of the same length. No counterexample can be constructed because the value is not attacker-controlled. The scanner incorrectly treats the output of strlen() on a kernel-registered string as tainted. This is a false positive.

ebt_obj_to_user() — net/bridge/netfilter/ebtables.c FP confidence=high

EBT_EXTENSION_MAXNAMELEN is a compile-time constant defined in the kernel headers (typically 32 bytes). The scanner incorrectly flagged it as user-controlled because it appears as an argument to copy_to_user(), but it is not derived from any user-supplied or server-supplied data. The source buffer 'name' is a local stack array of exactly EBT_EXTENSION_MAXNAMELEN bytes, initialized to zero and filled via strscpy(). Copying EBT_EXTENSION_MAXNAMELEN bytes from a buffer of exactly that size is safe. The taint trace from copy_to_user() returning a value is a scanner artifact — the return value of copy_to_user() is a boolean success/failure indicator, not a size or buffer pointer, and is only used as part of the error-check OR chain.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 1458
Taint snippetif (copy_to_user(um, name, EBT_EXTENSION_MAXNAMELEN) ||
Tainted varEBT_EXTENSION_MAXNAMELEN
Unvalidated sizecopy_to_user() arg 2 line 1458 — size EBT_EXTENSION_MAXNAMELEN
Sink snippetif (copy_to_user(um, name, EBT_EXTENSION_MAXNAMELEN) ||
Possibly guardedno
Dismissed: EBT_EXTENSION_MAXNAMELEN is a kernel-internal compile-time constant, not a user-supplied or server-supplied value. The scanner misidentified it as tainted, likely because the taint propagation tracked the copy_to_user() call itself as a taint source and then re-encountered the constant in the same expression. The local 'name' array is exactly EBT_EXTENSION_MAXNAMELEN bytes, so copying that many bytes from it is correct and safe. No counterexample can be constructed because no runtime value is involved — the size is fixed at compile time. This is a false positive.

encrypt_authorizer() — net/ceph/auth_x.c FP confidence=high

The le32_to_cpu() at line 357 reads msg_a->ticket_blob.blob_len, which was written by the kernel itself via cpu_to_le32(ticket_blob_len) in ceph_x_build_authorizer() before encrypt_authorizer() is called. The buffer au->buf is allocated with maxlen = sizeof(*msg_a) + ticket_blob_len + ceph_x_encrypt_buflen(&au->session_key, sizeof(*msg_b)), which precisely accounts for all offsets. In the second call site (ceph_x_add_authorizer_challenge), the authorizer was previously built by ceph_x_build_authorizer() so the same invariant holds. The blob_len value is locally controlled, not server-supplied, making all six findings false positives.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 357
Taint snippetp = (void *)(msg_a + 1) + le32_to_cpu(msg_a->ticket_blob.blob_len);
Tainted varmsg_b
Pointer derefmsg_b->struct_v line 361
Sink snippetmsg_b->struct_v = 2;
Possibly guardedno
Dismissed: blob_len is written locally by the kernel as cpu_to_le32(ticket_blob_len) and the buffer is allocated to exactly fit sizeof(*msg_a)+ticket_blob_len+ceph_x_encrypt_buflen(...). No counterexample exists: any value that could be placed in blob_len must have been placed there by the kernel and matches the allocation. msg_b->struct_v write is within bounds.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 357
Taint snippetp = (void *)(msg_a + 1) + le32_to_cpu(msg_a->ticket_blob.blob_len);
Tainted varmsg_b
Pointer derefmsg_b->nonce line 362
Sink snippetmsg_b->nonce = cpu_to_le64(au->nonce);
Possibly guardedno
Dismissed: Same reasoning as finding #1. msg_b->nonce write is within the locally-allocated buffer whose size accounts for all offsets.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 357
Taint snippetp = (void *)(msg_a + 1) + le32_to_cpu(msg_a->ticket_blob.blob_len);
Tainted varmsg_b
Pointer derefmsg_b->have_challenge line 364
Sink snippetmsg_b->have_challenge = 1;
Possibly guardedno
Dismissed: Same reasoning as finding #1. msg_b->have_challenge write is within bounds.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 357
Taint snippetp = (void *)(msg_a + 1) + le32_to_cpu(msg_a->ticket_blob.blob_len);
Tainted varmsg_b
Pointer derefmsg_b->server_challenge_plus_one line 365
Sink snippetmsg_b->server_challenge_plus_one =
Possibly guardedno
Dismissed: Same reasoning as finding #1. msg_b->server_challenge_plus_one write is within bounds.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 357
Taint snippetp = (void *)(msg_a + 1) + le32_to_cpu(msg_a->ticket_blob.blob_len);
Tainted varmsg_b
Pointer derefmsg_b->have_challenge line 368
Sink snippetmsg_b->have_challenge = 0;
Possibly guardedno
Dismissed: Same reasoning as finding #1. The else-branch msg_b->have_challenge=0 write is within bounds.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 357
Taint snippetp = (void *)(msg_a + 1) + le32_to_cpu(msg_a->ticket_blob.blob_len);
Tainted varmsg_b
Pointer derefmsg_b->server_challenge_plus_one line 369
Sink snippetmsg_b->server_challenge_plus_one = 0;
Possibly guardedno
Dismissed: Same reasoning as finding #1. The else-branch msg_b->server_challenge_plus_one=0 write is within bounds.

ceph_alloc_middle() — net/ceph/messenger.c VALIDATE confidence=medium

The middle_len value is read from a network-received message header (msg->hdr.middle_len), making it genuinely server-supplied. The call chain in ceph_con_in_msg_alloc() checks that middle_len is non-zero before calling ceph_alloc_middle(), and ceph_alloc_middle() itself BUG_ONs if middle_len is zero. However, there is no upper-bound check on middle_len before it is passed to kvmalloc(). A server could supply an arbitrarily large middle_len value (e.g., UINT32_MAX or near it), which would cause kvmalloc() to fail (returning NULL) rather than actually allocating that much memory, so in practice this is handled gracefully by the NULL check at line 2046. However, if kvmalloc() were to succeed with an absurdly large value, the buffer would be undersized relative to the actual data expected. The key question is whether there is a protocol-level or earlier validation that bounds middle_len to a sane maximum before this code is reached — that context is not visible here.

Finding #1 — Category B — cross-function via ceph_buffer_new() — BUG undersized_alloc

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 2038
Taint snippetint middle_len = le32_to_cpu(msg->hdr.middle_len);
Tainted varmiddle_len
Call siteline 2045 — passes middle_len to ceph_buffer_new()
Call snippetmsg->middle = ceph_buffer_new(middle_len, GFP_NOFS);
Sink (in callee)kvmalloc() line 20 (arg 0, role=size)
Sink snippetb->vec.iov_base = kvmalloc(len, gfp);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: With a very large middle_len, kvmalloc() will likely fail and return NULL, causing -ENOMEM and connection failure — benign in practice. However, if an attacker can supply a middle_len that is large enough to pass any unrelated protocol checks but small enough to succeed in allocation yet smaller than the actual data being received, subsequent data writes into msg->middle could write beyond the allocated buffer, causing heap corruption (KASAN: slab-out-of-bounds or memory corruption leading to kernel panic).
Fix: Add an upper-bound check on middle_len before calling ceph_alloc_middle() or inside it. For example, in ceph_con_in_msg_alloc() or ceph_alloc_middle(), validate: if (middle_len > CEPH_MSG_MAX_MIDDLE_LEN) return -EIO; where CEPH_MSG_MAX_MIDDLE_LEN is a reasonable protocol-defined constant (e.g., 16MB or whatever the Ceph protocol specifies as the maximum middle section size).
CVE pattern: Server-supplied length field used in allocation without upper-bound validation — similar in class to CVE-2020-25212 and other network protocol allocation size issues

alloc_msg_with_page_vector() — net/ceph/osd_client.c BUG confidence=high

alloc_msg_with_page_vector() receives a ceph_msg_header from the server (network packet) and directly uses server-supplied front_len and data_len without any upper-bound validation before passing them to allocation/page-vector functions. The hdr pointer is a received network buffer (this is the alloc_msg callback for incoming messages), so both fields are genuinely server-supplied. There is no cap on front_len before kvmalloc() or on data_len before the page allocation loop. A malicious server could send arbitrarily large values causing excessive memory allocation or OOM conditions.

Finding #1 — Category B — cross-function via ceph_msg_new2() — BUG undersized_alloc

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 5480
Taint snippetu32 front_len = le32_to_cpu(hdr->front_len);
Tainted varfront_len
Call siteline 5483 — passes front_len to ceph_msg_new2()
Call snippetm = ceph_msg_new2(type, front_len, 1, GFP_NOIO, false);
Sink (in callee)kvmalloc() line 1984 (arg 0, role=size)
Sink snippetm->front.iov_base = kvmalloc(front_len, flags);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: A malicious server sending an extremely large front_len (up to 4GB for u32) would cause kvmalloc() to attempt a huge allocation, likely failing with ENOMEM or causing system memory pressure/OOM kill. No panic, but denial-of-service via memory exhaustion.
Fix: Add an upper-bound check on front_len before calling ceph_msg_new2(): e.g., if (front_len > CEPH_MSG_MAX_FRONT_LEN) return NULL; where CEPH_MSG_MAX_FRONT_LEN is a reasonable protocol-defined maximum (e.g., 64KB or whatever the OSD protocol specifies).
CVE pattern: Server-supplied length field used directly in kernel allocation without upper-bound validation — similar pattern to CVE-2021-22543 style resource exhaustion via crafted network messages.

Finding #2 — Category F — cross-function via ceph_alloc_page_vector() — BUG undersized_alloc

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 5481
Taint snippetu32 data_len = le32_to_cpu(hdr->data_len);
Tainted vardata_len
Call siteline 5490 — passes data_len to ceph_alloc_page_vector()
Call snippetpages = ceph_alloc_page_vector(calc_pages_for(0, data_len),
Loopfor_loop line 47
Sink snippetfor (i = 0; i < num_pages; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: A malicious server sending a very large data_len would cause calc_pages_for(0, data_len) to return a huge page count, causing ceph_alloc_page_vector() to attempt to allocate a huge array of page pointers and then allocate that many individual pages, leading to massive memory consumption or OOM. With data_len near UINT_MAX, calc_pages_for could overflow producing a smaller-than-expected page count while data_len remains large, leading to an undersized page vector used with ceph_msg_data_add_pages().
Fix: Add an upper-bound check on data_len before using it: e.g., if (data_len > CEPH_MSG_MAX_DATA_LEN) { ceph_msg_put(m); return NULL; }. Also check for integer overflow in calc_pages_for(0, data_len) — ensure the page count does not wrap. A reasonable maximum should be enforced per protocol constraints.
CVE pattern: Server-supplied data length used to derive page allocation count without upper bound — denial-of-service via memory exhaustion, similar to resource exhaustion bugs in network filesystem clients.

get_reply() — net/ceph/osd_client.c FP confidence=high

The function properly validates server-supplied values: front_len is checked against preallocated size (line 5442), data_len is checked against data_length (line 5455). The taint propagation for finding #1 is incorrect — 'req' is retrieved from a kernel-internal RB-tree using the server-supplied 'tid' as a lookup key, but the retrieved object itself is kernel-allocated and kernel-controlled. The server cannot influence req->r_num_ops; this field was set when the kernel built the OSD request.

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

CategoryCat F — server value → loop iteration count
Taint sourcele64_to_cpu() line 5420
Taint snippetu64 tid = le64_to_cpu(hdr->tid);
Tainted varreq
Call siteline 5454 — passes req to sparse_data_requested()
Call snippetsrlen = sparse_data_requested(req);
Loopfor_loop line 5395
Sink snippetfor (i = 0; i < req->r_num_ops; ++i) {
Possibly guardedyes (heuristic)
Dismissed: The scanner incorrectly propagates taint from server-supplied 'tid' through the lookup_request() call to the returned 'req' pointer. However, req is a kernel-allocated ceph_osd_request struct created when the kernel issued the OSD request; the server only supplies the tid used as a lookup key. req->r_num_ops is set by kernel code and cannot be influenced by server data. No counterexample exists because the server has no path to write into req->r_num_ops. This is a classic false positive: using a tainted value as an index/key into a kernel data structure does not taint the retrieved kernel object.

handle_reply() — net/ceph/osd_client.c FP confidence=high

The function has strong validation: decode_MOSDOpReply() validates all decoded fields with bounds checks, m.num_ops is checked to equal the kernel-side req->r_num_ops before the loop, and req itself is a kernel-allocated structure looked up by tid (not populated from the server). The loop bound req->r_num_ops is kernel-controlled, not server-controlled. The scanner incorrectly propagated taint from le64_to_cpu(msg->hdr.tid) through lookup_request() to req->r_num_ops.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele64_to_cpu() line 3754
Taint snippetu64 tid = le64_to_cpu(msg->hdr.tid);
Tainted varreq
Loopfor_loop line 3844
Sink snippetfor (i = 0; i < req->r_num_ops; i++) {
Possibly guardedyes (heuristic)
Dismissed: The loop bound req->r_num_ops is from a kernel-allocated ceph_osd_request structure, not from the server message. The server-supplied m.num_ops is separately validated to equal req->r_num_ops at line 3839 before the loop. Array accesses m.rval[i] and m.outdata_len[i] are bounded by decode_MOSDOpReply()'s postcondition which guarantees num_ops <= ARRAY_SIZE(m->outdata_len). No counterexample can be constructed — all paths are protected. The taint propagation through lookup_request() is a scanner false positive.

osd_sparse_read() — net/ceph/osd_client.c FP confidence=high

The code uses a state machine. `count` is server-supplied but is bounded by a successful kmalloc_objs() allocation of exactly `count` elements in the EXTENTS state. convert_extent_map() traverses the same buffer with the same count immediately before the flagged loop, constituting a structurally equivalent prior full traversal. No counterexample exists where the loop could go OOB.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele32_to_cpu() line 5826
Taint snippetcount = le32_to_cpu((__force __le32)sr->sr_count);
Tainted varcount
Loopfor_loop line 5859
Sink snippetfor (i = 0; i < count; i++)
Possibly guardedyes (heuristic)
Dismissed: The allocation at line 5834 allocates exactly `count` elements (guarded by the count > sr->sr_ext_len check). sr->sr_count is set to count at line 5827, so on subsequent state machine re-entry, count (line 5808) equals the allocated size. convert_extent_map() at line 5851 performs a structurally identical traversal over [0, sr->sr_count) immediately before the flagged loop, which would fault first if the count were invalid. No counterexample can be constructed where the loop at 5859 exceeds the allocated array bounds.

prep_next_sparse_read() — net/ceph/osd_client.c FP confidence=high

The taint from le64_to_cpu(con->in_msg->hdr.tid) is used only to look up a kernel-allocated request object via lookup_request(). The returned req->r_num_ops and req->r_ops[] are locally-constructed kernel fields, not server-supplied values. The loop bound is the kernel-internal r_num_ops, which accurately reflects the allocated size of r_ops[]. The loop condition itself (++o->o_sparse_op_idx < req->r_num_ops) is a proper bounds check.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcele64_to_cpu() line 5725
Taint snippetreq = lookup_request(&o->o_requests, le64_to_cpu(con->in_msg->hdr.tid));
Tainted varreq
Loopwhile_loop line 5757
Sink snippetwhile (++o->o_sparse_op_idx < req->r_num_ops) {
Possibly guardedno
Dismissed: The server-supplied TID is used only as a lookup key into a radix/RB tree of locally-allocated ceph_osd_request objects. The req->r_num_ops field controlling the loop bound is set by the kernel at request construction time, not populated from any server response. No counterexample can be constructed because r_num_ops == allocated size of r_ops[], and the loop condition enforces this bound directly.

cmsghdr_from_user_compat_to_kern() — net/compat.c FP confidence=high

The function has a careful two-pass design. In the second pass, cmsg is copied atomically into a kernel-local struct, CMSG_COMPAT_OK validates cmsg.cmsg_len fits within the user message, and the line-189 guard verifies the output buffer has room for CMSG_ALIGN(tmp) bytes where tmp already includes sizeof(struct cmsghdr) plus the data length. This means CMSG_DATA(kcmsg) has sufficient space for (cmsg.cmsg_len - sizeof(*ucmsg)) bytes. No counterexample can be constructed that passes all guards and causes OOB.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 195
Taint snippetif (copy_from_user(CMSG_DATA(kcmsg),
Tainted var(cmsg.cmsg_len - sizeof(*ucmsg))
Unvalidated sizecopy_from_user() arg 2 line 195 — size (cmsg.cmsg_len - sizeof(*ucmsg))
Sink snippetif (copy_from_user(CMSG_DATA(kcmsg),
Possibly guardedno
Dismissed: cmsg is read atomically into a kernel local struct (no TOCTOU). CMSG_COMPAT_OK at line 186 validates cmsg.cmsg_len >= sizeof(*ucmsg) and fits within the user message. The guard at line 189 checks that CMSG_ALIGN(tmp) fits in remaining kernel buffer where tmp = (cmsg.cmsg_len - sizeof(*ucmsg)) + sizeof(struct cmsghdr). Since CMSG_ALIGN(tmp) >= sizeof(struct cmsghdr) + (cmsg.cmsg_len - sizeof(*ucmsg)), the CMSG_DATA(kcmsg) area (offset sizeof(struct cmsghdr) into kcmsg) has sufficient room for the copy. Could not construct a counterexample that bypasses all guards.

put_cmsg_compat() — net/compat.c FP confidence=high

The cmlen value in put_cmsg_compat() is derived from kernel-internal len parameter and capped by kmsg->msg_controllen. The check at line 234 ensures msg_controllen >= sizeof(*cm), which after the cap at line 264 ensures cmlen >= sizeof(struct compat_cmsghdr), preventing underflow. The len parameter comes from the kernel socket subsystem, not from user/server input. The scanner incorrectly flagged copy_to_user() as a taint source and traced the arithmetic through an already-bounded value.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 272
Taint snippetif (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
Tainted varcmlen - sizeof(struct compat_cmsghdr)
Unvalidated sizecopy_to_user() arg 2 line 272 — size cmlen - sizeof(struct compat_cmsghdr)
Sink snippetif (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
Possibly guardedno
Dismissed: cmlen is set to CMSG_COMPAT_LEN(len) (kernel-internal) and capped to kmsg->msg_controllen. The early guard at line 234 ensures msg_controllen >= sizeof(*cm); after the cap at line 264, cmlen >= sizeof(struct compat_cmsghdr) is guaranteed, so the subtraction cannot underflow. No counterexample can be constructed: to make cmlen < sizeof(compat_cmsghdr) you would need msg_controllen < sizeof(*cm), but that is caught at line 234-237 with early return. The taint source being copy_to_user() itself is a scanner artifact — copy_to_user is a sink, not a source of tainted data.

netdev_cmd_to_name() — net/core/dev.c FP confidence=high

The flagged access `ptype_base[ntohs(type) & PTYPE_HASH_MASK]` is a classic false positive. The value used as the array subscript is `ntohs(type) & PTYPE_HASH_MASK`. The bitwise AND with PTYPE_HASH_MASK is the bounds check: it masks the result to a fixed number of bits, guaranteeing the index is always within [0, PTYPE_HASH_MASK], which is exactly the size of the ptype_base array. No counterexample can be constructed — there is no value of ntohs(type) that, after being ANDed with PTYPE_HASH_MASK, could produce an out-of-bounds index.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 6157
Taint snippet&ptype_base[ntohs(type) &
Tainted varntohs(type) & PTYPE_HASH_MASK
Subscript[] line 6157
Sink snippet&ptype_base[ntohs(type) &
Possibly guardedno
Dismissed: The index `ntohs(type) & PTYPE_HASH_MASK` is inherently bounded by the bitwise AND. PTYPE_HASH_MASK is defined as (PTYPE_HASH_SIZE - 1) where PTYPE_HASH_SIZE is the length of ptype_base, so the mask operation is a perfect modulo that can never produce an out-of-bounds index. No counterexample exists: for any possible uint16_t value from ntohs(), applying & PTYPE_HASH_MASK yields a value in [0, PTYPE_HASH_MASK] ⊆ valid indices. This is a standard and correct bitmask-based bounds enforcement pattern. The static analyser flagged it purely because ntohs() returns a network-supplied value, but the subsequent masking makes it safe.

ptype_head() — net/core/dev.c FP confidence=high

The `ntohs(pt->type)` value is masked with `PTYPE_HASH_MASK` before being used as an array subscript. The bitwise AND operation guarantees the result is strictly bounded by `PTYPE_HASH_MASK`, which is defined as a power-of-two-minus-one mask (e.g., 0xF or 0x1F) corresponding exactly to the size of the `ptype_base` array. No counterexample can be constructed: for any 16-bit value of `pt->type`, `ntohs(pt->type) & PTYPE_HASH_MASK` is always in the range `[0, PTYPE_HASH_MASK]`, which is always a valid index into `ptype_base`. This is a textbook safe hash-table index computation. The scanner flagged it because `ntohs()` is a taint source, but the mask makes it safe regardless of the input value.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 608
Taint snippet&ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
Tainted varntohs(pt->type) & PTYPE_HASH_MASK
Subscript[] line 608
Sink snippet&ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
Possibly guardedno
Dismissed: The expression `ntohs(pt->type) & PTYPE_HASH_MASK` applies a bitmask before indexing. PTYPE_HASH_MASK is defined as (PTYPE_HASH_SIZE - 1) where PTYPE_HASH_SIZE is the compile-time size of the ptype_base array. For any possible 16-bit input value, the masked result is always in [0, PTYPE_HASH_MASK], which is always a valid array index. No counterexample exists — there is no input value that passes the mask and still produces an out-of-bounds index. This is a false positive.

__get_filter() — net/core/filter.c FP confidence=high

The function validates fprog->len via bpf_check_basics_ok() before allocation and copy. The allocation bpf_prog_size(fprog->len) sizes prog->insns to hold exactly fprog->len instructions, so fsize = bpf_classic_proglen(fprog) = fprog->len * sizeof(struct sock_filter) fits within the allocated buffer. The bounds check is both present and sufficient.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 1519
Taint snippetif (copy_from_user(prog->insns, fprog->filter, fsize)) {
Tainted varfsize
Unvalidated sizecopy_from_user() arg 2 line 1519 — size fsize
Sink snippetif (copy_from_user(prog->insns, fprog->filter, fsize)) {
Possibly guardedno
Dismissed: bpf_check_basics_ok() validates fprog->len is in [1, BPF_MAXINSNS] before the allocation and copy. bpf_prog_alloc(bpf_prog_size(fprog->len)) allocates exactly enough space for fprog->len instructions, which matches fsize = fprog->len * sizeof(struct sock_filter). No counterexample could be constructed: any len passing the basics check produces an allocation large enough for fsize bytes. The scanner flagged this because it did not trace through bpf_check_basics_ok() and the size-capacity relationship between bpf_prog_size() and bpf_classic_proglen().

bpf_prog_create_from_user() — net/core/filter.c FP confidence=high

bpf_check_basics_ok() at line 1434 validates fprog->len before any use of fsize. It ensures len is in [1, BPF_MAXINSNS], preventing integer overflow in fsize computation. Both bpf_prog_alloc (via bpf_prog_size) and copy_from_user (via bpf_classic_proglen) use len*8 bytes, so the destination buffer is always exactly large enough for the copy. No counterexample exists where the copy exceeds the allocation.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 1441
Taint snippetif (copy_from_user(fp->insns, fprog->filter, fsize)) {
Tainted varfsize
Unvalidated sizecopy_from_user() arg 2 line 1441 — size fsize
Sink snippetif (copy_from_user(fp->insns, fprog->filter, fsize)) {
Possibly guardedno
Dismissed: bpf_check_basics_ok() validates fprog->len in [1, BPF_MAXINSNS] before fsize is used. fsize = fprog->len * sizeof(struct sock_filter) and the allocation is bpf_prog_size(fprog->len) = sizeof(struct bpf_prog) + fprog->len * sizeof(struct bpf_insn). Since sizeof(struct sock_filter) == sizeof(struct bpf_insn) == 8 bytes on all supported architectures, the copy destination (fp->insns) is always exactly large enough. No counterexample can be constructed — the guard is tight and sufficient.

ptype_seq_next() — net/core/net-procfs.c FP confidence=high

The scanner incorrectly treats ntohs(pt->type) as server-supplied data. Here pt is a kernel-internal struct packet_type registered via dev_add_pack() or similar — its type field is set by the kernel, not received from the network. Furthermore, the & PTYPE_HASH_MASK operation mathematically constrains hash to [0, PTYPE_HASH_SIZE-1], making any out-of-bounds access impossible. The while loop's ++hash check (line 279) guards the line 281 access. Both findings are false positives.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 276
Taint snippethash = ntohs(pt->type) & PTYPE_HASH_MASK;
Tainted varhash
Subscript[] line 278
Sink snippetwhile (nxt == &ptype_base[hash]) {
Possibly guardedno
Dismissed: pt->type is a kernel-internal protocol identifier stored in network byte order in struct packet_type. The & PTYPE_HASH_MASK bitmask guarantees hash is in [0, PTYPE_HASH_SIZE-1]. No counterexample exists: any 16-bit value ANDed with PTYPE_HASH_MASK (= PTYPE_HASH_SIZE-1) is strictly less than PTYPE_HASH_SIZE. False positive.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 276
Taint snippethash = ntohs(pt->type) & PTYPE_HASH_MASK;
Tainted varhash
Subscript[] line 281
Sink snippetnxt = READ_ONCE(ptype_base[hash].next);
Possibly guardedyes (heuristic)
Dismissed: Same analysis as finding #1 for the initial value of hash. Additionally, line 279 explicitly checks `if (++hash >= PTYPE_HASH_SIZE) return NULL` before reaching line 281, providing a second layer of protection for the incremented value. No counterexample exists. False positive.

pf() — net/core/pktgen.c FP confidence=high

All four findings are false positives. Findings #1-#3 are based on incorrect taint attribution: the scanner confused separate code paths (IPv4 destination address computation using ntohl() vs. IMIX packet size selection using get_random_u32_below()). The value 't' at line 2654 comes from get_random_u32_below(IMIX_PRECISION), a kernel RNG bounded call, not from ntohl(). The entry_index is a kernel-internal value written by fill_imix_distribution(). Finding #4 is a false positive because 'max' is computed as min(count, sizeof(data)-1), explicitly bounded to fit within the destination buffer.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 2654
Taint snippet__u8 entry_index = pkt_dev->imix_distribution[t];
Tainted varentry_index
Truncationline 2654: 32 → 8-bit __u8
Sink snippet__u8 entry_index = pkt_dev->imix_distribution[t];
Possibly guardedno
Dismissed: The scanner incorrectly attributes taint from ntohl() at line 2588 (IPv4 dst address path) to line 2654 (IMIX path). These are separate else-if branches. The value 't' at line 2654 is from get_random_u32_below(IMIX_PRECISION), which is kernel-internal and bounded. entry_index is a __u8 loaded from imix_distribution[], which is filled by kernel-internal fill_imix_distribution(). No server-supplied data involved.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 2588
Taint snippetimn = ntohl(pkt_dev->daddr_min);
Tainted vart
Subscript[] line 2654
Sink snippet__u8 entry_index = pkt_dev->imix_distribution[t];
Possibly guardedno
Dismissed: Same misattribution as finding #1. The taint source ntohl() at line 2588 is in the IPv4 destination address computation branch, which is mutually exclusive with the IMIX branch at line 2651. The subscript 't' at line 2654 is bounded by IMIX_PRECISION via get_random_u32_below().

Finding #3 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 2588
Taint snippetimn = ntohl(pkt_dev->daddr_min);
Tainted varentry_index
Subscript[] line 2656
Sink snippetentry = &pkt_dev->imix_entries[entry_index];
Possibly guardedno
Dismissed: Same misattribution. entry_index is loaded from imix_distribution[] which is a kernel-internal array filled by fill_imix_distribution(). While there could theoretically be a kernel-internal logic bug in fill_imix_distribution() (j could reach n_imix_entries), this is not a server-supplied/user-supplied taint issue as the scanner claims.

Finding #4 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 533
Taint snippetif (copy_from_user(data, buf, max))
Tainted varmax
Unvalidated sizecopy_from_user() arg 2 line 533 — size max
Sink snippetif (copy_from_user(data, buf, max))
Possibly guardedno
Dismissed: max = min(count, sizeof(data) - 1) explicitly caps the copy length to 127 bytes, which fits within data[128]. The copy_from_user call is safe. The size is not user-controlled beyond the min() cap.

skb_checksum_setup_ipv6() — net/core/skbuff.c FP confidence=high

The function uses per-iteration bounds validation via skb_maybe_pull_tail() before any header pointer dereference. Even though 'len' is derived from a server-supplied payload_len without explicit range validation against the actual skb length, each loop iteration calls skb_maybe_pull_tail() which verifies that the required bytes are actually present in the skb before proceeding. If the packet is too short or payload_len is inflated, skb_maybe_pull_tail returns a negative error, triggering 'goto out'. The MAX_IPV6_HDR_LEN cap (576 bytes) further limits pull operations. No OOB access is possible because no pointer dereference occurs without a successful skb_maybe_pull_tail check immediately preceding it.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 5955
Taint snippetlen = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
Tainted varlen
Loopwhile_loop line 5956
Sink snippetwhile (off <= len && !done) {
Possibly guardedno
Dismissed: Attempted counterexample: payload_len=65535 makes len=65575, but the loop body calls skb_maybe_pull_tail(skb, off+sizeof(header), MAX_IPV6_HDR_LEN) before dereferencing any header pointer. If off+sizeof(header) exceeds available skb data, this returns -EPROTO or similar negative value, causing 'goto out' before any OOB access. No counterexample found — the per-iteration validation is sufficient protection regardless of the value of 'len'.

skb_mpls_dec_ttl() — net/core/skbuff.c FP confidence=high

The function correctly validates that the skb contains enough data via pskb_may_pull() before accessing the MPLS header. The TTL field is extracted with a bitmask (MPLS_LS_TTL_MASK = 0xFF) that limits the result to exactly 8 bits before assignment to u8 ttl, so no truncation occurs. The scanner flagged a 32→8 bit narrowing but missed that the masking makes the narrowing safe. The subsequent decrement-and-zero check also prevents forwarding with a zero TTL.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcebe32_to_cpu() line 6737
Taint snippetttl = (lse & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT;
Tainted varttl
Truncationline 6737: 32 → 8-bit u8
Sink snippetttl = (lse & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT;
Possibly guardedno
Dismissed: The RHS expression applies MPLS_LS_TTL_MASK (0x000000FF) before the right-shift by MPLS_LS_TTL_SHIFT (0), so the result is always in [0, 255] — exactly the range of u8. No counterexample exists where the 32-bit intermediate value exceeds 255 after masking. The scanner's own guidance states this is a false positive when masking limits the value to the destination width before assignment.

sock_ioctl_inout() — net/core/sock.c FP confidence=high

sock_ioctl_inout() is a kernel-internal helper; 'size' is passed by the kernel caller, not read from user space. The scanner incorrectly treats 'size' as user-controlled because it appears in copy_from_user(), but 'size' is a kernel-supplied parameter whose value is determined by the calling context (e.g., sizeof(struct ifreq) or similar compile-time constant passed by sock_do_ioctl or equivalent). The actual user-supplied data is 'arg' (the user pointer), not 'size'. Both copy_from_user() and copy_to_user() use the same kernel-controlled 'size' for 'karg', which was also allocated by the kernel caller to exactly that size. No user-controlled size is involved.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 4495
Taint snippetif (copy_from_user(karg, arg, size))
Tainted varsize
Unvalidated sizecopy_from_user() arg 2 line 4495 — size size
Sink snippetif (copy_from_user(karg, arg, size))
Possibly guardedno
Dismissed: The 'size' parameter is a kernel-internal value passed by the kernel caller (not derived from user input). The scanner misidentifies copy_from_user() as a taint source for 'size', but 'size' is the third argument to copy_from_user(), not a value read from user space. The taint source trace is erroneous: copy_from_user() taints 'karg' (the destination buffer), not 'size'. This is a false positive due to the scanner confusing the size parameter of copy_from_user with user-supplied data.

Finding #2 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 4502
Taint snippetif (copy_to_user(arg, karg, size))
Tainted varsize
Unvalidated sizecopy_to_user() arg 2 line 4502 — size size
Sink snippetif (copy_to_user(arg, karg, size))
Possibly guardedno
Dismissed: Same reasoning as finding #1. 'size' in copy_to_user() is kernel-controlled, matching the size used for 'karg' allocation by the caller. The scanner's taint propagation is incorrect here — copy_to_user() does not introduce 'size' as a tainted value, and 'size' was never read from user space in this function. False positive.

ar9331_tag_rcv() — net/dsa/tag_ar9331.c FP confidence=high

Both findings are false positives. FIELD_GET() applies a bitmask (the _MASK constant) to extract a sub-field from the 16-bit hdr value before assignment. The extracted bits are always narrower than or equal to 8 bits, so no truncation of meaningful bits occurs. For 'ver': AR9331_HDR_VERSION_MASK extracts only the version field bits, and the subsequent check against AR9331_HDR_VERSION ensures only valid values proceed. For 'port': AR9331_HDR_PORT_NUM_MASK extracts only the port number bits (AR9331 switch has a small number of ports, far fewer than 256), and dsa_conduit_find_user() returns NULL for invalid ports, causing safe early exit.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 61
Taint snippetver = FIELD_GET(AR9331_HDR_VERSION_MASK, hdr);
Tainted varver
Truncationline 61: 16 → 8-bit u8
Sink snippetver = FIELD_GET(AR9331_HDR_VERSION_MASK, hdr);
Possibly guardedno
Dismissed: FIELD_GET(AR9331_HDR_VERSION_MASK, hdr) applies the mask before assignment, so the 8-bit 'ver' variable holds only the masked bits. The mask limits the value to fit in u8. Additionally, the subsequent check 'ver != AR9331_HDR_VERSION' drops any packet with an unexpected version value. No counterexample can be constructed: any value that passes FIELD_GET masking is bounded by the mask width, and the version equality check further constrains it. False positive.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 79
Taint snippetport = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr);
Tainted varport
Truncationline 79: 16 → 8-bit u8
Sink snippetport = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr);
Possibly guardedno
Dismissed: FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr) masks the port bits from 'hdr' before assignment to u8 'port'. The AR9331 switch has at most 6 ports, and the port number field in the header is only a few bits wide — well within u8 range after masking. dsa_conduit_find_user(ndev, 0, port) returns NULL for any port not registered as a DSA user, and the NULL check at line 82 causes safe packet drop. No counterexample possible: the mask prevents truncation loss, and the NULL guard prevents use of invalid port values. False positive.

ksz_xmit_timestamp() — net/dsa/tag_ksz.c FP confidence=high

The function reads a PTP correction field from a network packet, but the subsequent arithmetic is carefully bounded. The tv_sec field is masked to 2 bits, tv_nsec is guaranteed [0, 999999999] by ns_to_timespec64(), and the OR of these two values into tstamp_raw always fits within 32 bits with no overlap between the bit fields used.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourceget_unaligned_be64() line 240
Taint snippettstamp_raw = ((ts.tv_sec & 3) << 30) | ts.tv_nsec;
Tainted vartstamp_raw
Truncationline 240: 64 → 32-bit u32
Sink snippettstamp_raw = ((ts.tv_sec & 3) << 30) | ts.tv_nsec;
Possibly guardedno
Dismissed: The taint originates from a network PTP packet, but the computation is bounded by design: (1) only the `correction < 0` branch executes; (2) ns_to_timespec64() guarantees tv_nsec in [0, 999999999] < 2^30; (3) tv_sec is masked with & 3 giving max 3; (4) (3 << 30) | 999999999 = 4221225471 which is well within u32 range (4294967295). The bit fields are non-overlapping (tv_sec uses bits 30-31, tv_nsec uses bits 0-29), so no counterexample exists that would overflow u32.

qca_tag_rcv() — net/dsa/tag_qca.c FP confidence=high

Both findings are false positives. FIELD_GET() is a kernel macro that extracts a bitfield using a mask and right-shift, so the result is always bounded by the bitfield width — not the full 16-bit source width. QCA_HDR_RECV_VERSION and QCA_HDR_RECV_TYPE are narrow bitfields within the 16-bit header; FIELD_GET() masks and shifts before assignment, meaning the resulting value in 'ver' and 'pk_type' is inherently limited to the number of bits defined by those field masks, regardless of the destination type being u8. The scanner's concern that a 16-bit value is silently truncated to 8-bit is not applicable because FIELD_GET() already performs the necessary masking. Furthermore, 'ver' is immediately checked against the expected constant QCA_HDR_VERSION, and 'pk_type' is compared against known enum values — any out-of-range value simply falls through to the 'port' extraction path, which is further validated by dsa_conduit_find_user() returning NULL on invalid ports.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 58
Taint snippetver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr);
Tainted varver
Truncationline 58: 16 → 8-bit u8
Sink snippetver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr);
Possibly guardedno
Dismissed: FIELD_GET(QCA_HDR_RECV_VERSION, hdr) applies a compile-time mask and right-shift derived from the field definition, so the result is bounded to the bitfield width before being stored in 'ver'. The truncation from 16-bit to u8 is safe because FIELD_GET guarantees the value fits within the field width. Additionally, 'ver' is immediately compared to QCA_HDR_VERSION and the packet is dropped if they differ — no counterexample exists where an unexpected 'ver' value could cause harm beyond dropping the packet. False positive.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 65
Taint snippetpk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr);
Tainted varpk_type
Truncationline 65: 16 → 8-bit u8
Sink snippetpk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr);
Possibly guardedno
Dismissed: FIELD_GET(QCA_HDR_RECV_TYPE, hdr) masks and shifts to extract only the type bitfield, so 'pk_type' is bounded by the field width before truncation to u8. The code checks 'pk_type' against QCA_HDR_RECV_TYPE_RW_REG_ACK and QCA_HDR_RECV_TYPE_MIB; any unexpected value falls through to port extraction, which is validated by dsa_conduit_find_user() returning NULL on an invalid port (causing the packet to be dropped). No counterexample can be constructed where pk_type causes an OOB or dangerous operation. False positive.

rtl4a_tag_rcv() — net/dsa/tag_rtl4_a.c FP confidence=high

Both findings are false positives. In finding #1, the RHS expression explicitly masks with & 0x0f before assignment to prot, limiting the value to 4 bits (0-15), which trivially fits in a u8. In finding #2, the RHS expression explicitly masks with & 0xff before assignment to port, which is exactly the range of a u8 (0-255). The masking in both cases is the canonical way to intentionally and safely narrow a wider value — the scanner's own note says to flag as false positive when masking limits the value to the destination width, which is exactly what happens here. No counterexample can be constructed for either case: for prot, any 16-bit input after the shift and & 0x0f yields 0-15, always safe in u8; for port, any 16-bit input after & 0xff yields 0-255, always safe in u8. The subsequent use of 'port' in dsa_conduit_find_user() is also safe because DSA port numbers are typically bounded by the switch's port count, and dsa_conduit_find_user() handles not-found ports by returning NULL (checked at line 103).

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 94
Taint snippetprot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f;
Tainted varprot
Truncationline 94: 16 → 8-bit u8
Sink snippetprot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f;
Possibly guardedno
Dismissed: The expression '(protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f' explicitly masks the shifted result to 4 bits before storing in prot (u8). The mask & 0x0f guarantees the value is in [0, 15], well within u8 range. No truncation hazard exists. Cannot construct a counterexample: for any 16-bit protport, after shifting and masking with 0x0f the result is always 0-15.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 100
Taint snippetport = protport & 0xff;
Tainted varport
Truncationline 100: 16 → 8-bit u8
Sink snippetport = protport & 0xff;
Possibly guardedno
Dismissed: The expression 'protport & 0xff' explicitly masks to 8 bits before storing in port (u8). This is exactly the representable range of u8 (0-255), so no truncation or information loss occurs. The scanner's own false-positive note applies directly here: masking with & 0xFF limits the value to destination width. Cannot construct a counterexample: any 16-bit protport after & 0xff is 0-255, always representable in u8.

rtl8_4_read_tag() — net/dsa/tag_rtl8_4.c FP confidence=high

All three findings involve FIELD_GET() which masks the 16-bit ntohs() value to the specific bitfield defined by the mask before assignment to u8. The masking ensures no information is lost in truncation if the field is ≤8 bits wide. Furthermore: proto and reason are only used in equality comparisons (no memory ops), and port is used only as an argument to dsa_conduit_find_user() which returns NULL for invalid ports (handled with -ENOENT). No OOB access is possible.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 176
Taint snippetproto = FIELD_GET(RTL8_4_PROTOCOL, ntohs(tag16[1]));
Tainted varproto
Truncationline 176: 16 → 8-bit u8
Sink snippetproto = FIELD_GET(RTL8_4_PROTOCOL, ntohs(tag16[1]));
Possibly guardedno
Dismissed: FIELD_GET(RTL8_4_PROTOCOL, ntohs(tag16[1])) masks the value to the protocol bitfield before assignment. The result is only used in an equality comparison against RTL8_4_PROTOCOL_RTL8365MB with no memory operations. No counterexample can be constructed where a truncated value passes the check when the full value would not, because FIELD_GET's masking ensures only the relevant bits remain before any truncation occurs.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 185
Taint snippetreason = FIELD_GET(RTL8_4_REASON, ntohs(tag16[1]));
Tainted varreason
Truncationline 185: 16 → 8-bit u8
Sink snippetreason = FIELD_GET(RTL8_4_REASON, ntohs(tag16[1]));
Possibly guardedno
Dismissed: FIELD_GET(RTL8_4_REASON, ntohs(tag16[1])) masks the value to the reason bitfield. The variable 'reason' is only compared against RTL8_4_REASON_TRAP with no array indexing or memory operations. Even if the value exceeds u8 range after masking (impossible if the field is ≤8 bits), the only consequence is a boolean branch decision — no memory safety issue exists.

Finding #3 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 188
Taint snippetport = FIELD_GET(RTL8_4_TX, ntohs(tag16[3]));
Tainted varport
Truncationline 188: 16 → 8-bit u8
Sink snippetport = FIELD_GET(RTL8_4_TX, ntohs(tag16[3]));
Possibly guardedno
Dismissed: FIELD_GET(RTL8_4_TX, ntohs(tag16[3])) masks the value to the TX port bitfield. The result is passed to dsa_conduit_find_user() which performs its own internal port validation and returns NULL for non-existent ports. The NULL return is explicitly checked (lines 190-195) with -ENOENT returned on failure. No counterexample exists: any port value that maps to no user device causes NULL return and early exit without any memory corruption.

sja1110_rcv_inband_control_extension() — net/dsa/tag_sja1105.c BUG confidence=medium

The function validates only the minimal SJA1110_HEADER_LEN bytes via pskb_may_pull before parsing rx_header. When the metadata path is taken (RX_HEADER_IS_METADATA), the n_ts field extracted from rx_header is used as an unbounded loop iteration count with no validation that (n_ts+1)*SJA1110_META_TSTAMP_SIZE bytes are actually available in the skb buffer.

Finding #1 — Category F — cross-function via sja1110_rcv_meta() — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 592
Taint snippetrx_header = ntohs(*(__be16 *)skb->data);
Tainted varrx_header
Call siteline 598 — passes rx_header to sja1110_rcv_meta()
Call snippetreturn sja1110_rcv_meta(skb, rx_header);
Loopfor_loop line 555
Sink snippetfor (i = 0; i <= n_ts; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sja1110_rcv_meta() when a crafted packet has a large N_TS field causing the loop to read past the end of the skb data buffer
Fix: In sja1110_rcv_meta(), after extracting n_ts, validate that the skb contains at least SJA1110_HEADER_LEN + (n_ts + 1) * SJA1110_META_TSTAMP_SIZE bytes (using pskb_may_pull or by checking skb->len against the required length) before entering the loop.
CVE pattern: Network-supplied loop bound without buffer length validation — similar to various DSA/network tag parsing OOB read patterns

ethtool_cmis_cdb_execute_epl_cmd() — net/ethtool/cmis_cdb.c FP confidence=medium

The `args->req` struct is a CDB request being constructed by the kernel to send TO the optical module, not a response received FROM it. The `be16_to_cpu(args->req.epl_len)` converts a big-endian field that was set by the kernel's own firmware-update code (CMIS uses big-endian wire format even for locally-constructed requests). The loop bounds are controlled by kernel-supplied firmware image data, not by an external server. Additionally, the loops have structural termination conditions bounded by hardware page/offset constants (CMIS_CDB_EPL_PAGE_END, CMIS_CDB_EPL_FW_BLOCK_OFFSET_END) and a min() calculation that prevents oversized individual writes.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcebe16_to_cpu() line 572
Taint snippetu16 epl_len = be16_to_cpu(args->req.epl_len);
Tainted varepl_len
Loopfor_loop line 577
Sink snippetfor (page = CMIS_CDB_EPL_PAGE_START;
Possibly guardedno
Dismissed: epl_len is stored in big-endian in the locally-constructed CDB request struct (CMIS protocol uses BE format). The kernel sets epl_len to the actual EPL data size before calling this function. The outer loop is also bounded by hardware constants (CMIS_CDB_EPL_PAGE_END). No counterexample possible given locally-controlled data. False positive per pattern #1.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcebe16_to_cpu() line 572
Taint snippetu16 epl_len = be16_to_cpu(args->req.epl_len);
Tainted varepl_len
Loopwhile_loop line 581
Sink snippetwhile (offset <= CMIS_CDB_EPL_FW_BLOCK_OFFSET_END &&
Possibly guardedno
Dismissed: Same reasoning as finding #1. The inner while loop is additionally bounded by CMIS_CDB_EPL_FW_BLOCK_OFFSET_END (a hardware constant) and bytes_to_write is capped by min() of space_left and read_write_len_ext. The taint source is a locally-written big-endian field in a kernel-constructed request, not an externally-received value.

ethtool_copy_validate_indir() — net/ethtool/ioctl.c FP confidence=high

The 'size' parameter in ethtool_copy_validate_indir() originates from the kernel driver via ops->get_rxfh_indir_size(dev), not from user space. The destination buffer 'indir' is allocated with kcalloc() using that exact same kernel-controlled size. User-supplied sizes are validated against the kernel-known size before the call is made (line 1386 in ethtool_set_rxfh_indir). The copy_from_user uses the kernel-controlled size, which matches the allocation. No OOB is possible.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 1293
Taint snippetif (copy_from_user(indir, useraddr, array_size(size, sizeof(indir[0]))))
Tainted vararray_size(size, sizeof(indir[0]))
Unvalidated sizecopy_from_user() arg 2 line 1293 — size array_size(size, sizeof(indir[0]))
Sink snippetif (copy_from_user(indir, useraddr, array_size(size, sizeof(indir[0]))))
Possibly guardedno
Dismissed: The scanner confuses 'size' as user-supplied because it's a parameter, but at both call sites it is set to the kernel-driver-reported indir size (ops->get_rxfh_indir_size(dev)), and the destination buffer is kcalloc'd with that exact size. User-supplied sizes are gated by equality checks against the kernel size before reaching the call. No counterexample can be constructed — the copy size always matches the allocation size.

ethtool_get_dump_data() — net/ethtool/ioctl.c FP confidence=high

The value 'len' is computed as min(tmp.len, dump.len) where tmp.len is kernel/driver-supplied and dump.len is user-supplied. The min() operation ensures len never exceeds tmp.len, which is exactly the size of the vzalloc'd buffer. The copy_to_user copies at most tmp.len bytes from a tmp.len-sized buffer — no OOB is possible. The destination is userspace, so user-controlled destination addresses are the user's own concern.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 2835
Taint snippetif (copy_to_user(useraddr, data, len))
Tainted varlen
Unvalidated sizecopy_to_user() arg 2 line 2835 — size len
Sink snippetif (copy_to_user(useraddr, data, len))
Possibly guardedno
Dismissed: len = min(tmp.len, dump.len) where tmp.len is the driver-reported dump size used to size the vzalloc allocation. Since len ≤ tmp.len = size of data buffer, copy_to_user(useraddr, data, len) never reads beyond the allocated buffer. No counterexample exists: any user-supplied dump.len either gets capped by min() at tmp.len (safe) or is smaller than tmp.len (also safe). False positive from static analysis not modeling the min() constraint.

ethtool_get_features() — net/ethtool/ioctl.c FP confidence=high

The function reads copy_size from userspace but immediately clamps it at line 110-111 to at most ETHTOOL_DEV_FEATURE_WORDS before using it in the copy_to_user call. The source buffer 'features' has exactly ETHTOOL_DEV_FEATURE_WORDS elements, so copy_size * sizeof(*features) can never exceed the buffer size. The scanner failed to recognize this clamping as a sufficient bounds check.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 116
Taint snippetif (copy_to_user(useraddr, features,
Tainted vararray_size(copy_size, sizeof(*features))
Unvalidated sizecopy_to_user() arg 2 line 116 — size array_size(copy_size, sizeof(*features))
Sink snippetif (copy_to_user(useraddr, features,
Possibly guardedno
Dismissed: copy_size is read from userspace (user-controlled) but is clamped at lines 110-111: 'if (copy_size > ETHTOOL_DEV_FEATURE_WORDS) copy_size = ETHTOOL_DEV_FEATURE_WORDS'. Since copy_size is u32, it cannot be negative, and the upper bound is enforced before use. No counterexample can be constructed: any value > ETHTOOL_DEV_FEATURE_WORDS is reduced to ETHTOOL_DEV_FEATURE_WORDS, making array_size(copy_size, sizeof(*features)) always ≤ sizeof(features). The finding is a false positive.

ethtool_get_phy_stats() — net/ethtool/ioctl.c FP confidence=medium

stats.n_stats is read from userspace initially, but the helper functions ethtool_get_phy_stats_phydev() and ethtool_get_phy_stats_ethtool() overwrite stats.n_stats with the kernel-determined actual stat count and allocate data[] accordingly. The copy_to_user size thus reflects the kernel-controlled allocation size, not the raw user-supplied value. This is the standard ethtool pattern.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 2660
Taint snippetcopy_to_user(useraddr, data,
Tainted vararray_size(stats.n_stats, sizeof(u64))
Unvalidated sizecopy_to_user() arg 2 line 2660 — size array_size(stats.n_stats, sizeof(u64))
Sink snippetcopy_to_user(useraddr, data,
Possibly guardedno
Dismissed: stats.n_stats originates from copy_from_user, making the scanner flag it as tainted. However, the ethtool helper functions (ethtool_get_phy_stats_phydev/ethtool_get_phy_stats_ethtool) follow the standard ethtool pattern of overwriting stats.n_stats with the actual driver-reported count and allocating data[] with vzalloc(stats.n_stats * sizeof(u64)) based on that count. By the time copy_to_user is reached, stats.n_stats is kernel-controlled and matches the allocation. No counterexample exists where stats.n_stats could exceed the data[] buffer size at the copy_to_user call. The implicit n_stats > 0 guard at line 2659 also prevents zero-count copies.

ethtool_get_sset_info() — net/ethtool/ioctl.c FP confidence=high

The function is carefully designed: n_bits = hweight64(sset_mask) counts the set bits in the user-supplied mask (bounded 0-64). info_buf is allocated with exactly n_bits u32 slots. idx increments only when a bit from sset_mask is processed, so idx <= n_bits always. The copy_to_user at line 841 uses array_size(idx, sizeof(u32)) which is always <= n_bits*sizeof(u32) = the allocation size. No OOB is possible.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 841
Taint snippetif (copy_to_user(useraddr, info_buf, array_size(idx, sizeof(u32))))
Tainted vararray_size(idx, sizeof(u32))
Unvalidated sizecopy_to_user() arg 2 line 841 — size array_size(idx, sizeof(u32))
Sink snippetif (copy_to_user(useraddr, info_buf, array_size(idx, sizeof(u32))))
Possibly guardedno
Dismissed: idx is derived from user-supplied sset_mask but is structurally bounded: idx can increment at most once per set bit in sset_mask, and n_bits = hweight64(sset_mask) counts exactly those bits. info_buf is allocated with n_bits elements, so idx <= n_bits always holds. Attempted counterexample: no assignment of sset_mask can make idx exceed n_bits since the loop iterates only over bits already in sset_mask. The scanner correctly identifies the taint source but misses that idx is upper-bounded by n_bits (the allocation count). False positive.

ethtool_get_stats() — net/ethtool/ioctl.c FP confidence=high

The function reads stats.n_stats from userspace via copy_from_user, but immediately overwrites it at lines 2539-2542 with either 0 or the kernel-computed n_stats value (which itself is bounded by the S32_MAX/sizeof(u64) check at line 2533). The tainted user-supplied value is never actually used in any memory operation — only the sanitised kernel value is. The allocation size and copy size both use the same kernel-controlled stats.n_stats, so no overflow or mismatch is possible.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 2558
Taint snippetcopy_to_user(useraddr, data,
Tainted vararray_size(stats.n_stats, sizeof(u64))
Unvalidated sizecopy_to_user() arg 2 line 2558 — size array_size(stats.n_stats, sizeof(u64))
Sink snippetcopy_to_user(useraddr, data,
Possibly guardedno
Dismissed: stats.n_stats is unconditionally overwritten at lines 2539-2542 with either 0 or n_stats (the kernel-driver-returned value). The user-supplied stats.n_stats is used only as a hint to detect mismatch, never as a size operand. n_stats is bounded by the S32_MAX/sizeof(u64) check. The vzalloc and copy_to_user both use the same stats.n_stats value. No counterexample exists: any user-supplied stats.n_stats value results in stats.n_stats being set to 0 or n_stats, never an arbitrary large number. False positive.

ethtool_get_tunable() — net/ethtool/ioctl.c FP confidence=high

ethtool_tunable_valid() validates tuna.len against the expected size for the given tunable type and id before the allocation and copy. The kzalloc() allocates exactly tuna.len bytes, and copy_to_user() copies exactly tuna.len bytes from that allocation — no OOB is possible. The validator constrains tuna.len to small, known values matching specific tunable types.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 2984
Taint snippetif (copy_to_user(useraddr, data, tuna.len))
Tainted vartuna.len
Unvalidated sizecopy_to_user() arg 2 line 2984 — size tuna.len
Sink snippetif (copy_to_user(useraddr, data, tuna.len))
Possibly guardedno
Dismissed: tuna.len is user-supplied, but ethtool_tunable_valid() checks that len matches the expected size for the given tunable id and type_id (e.g., sizeof(u32) for numeric tunables). After validation, kzalloc(tuna.len) allocates exactly tuna.len bytes, and copy_to_user uses the same tuna.len as the size — perfectly bounded to the allocation. No counterexample exists: any tuna.len passing the validator is a small, kernel-expected constant, and data is allocated to exactly that size.

ethtool_rxnfc_copy_from_compat() — net/ethtool/ioctl.c FP confidence=high

The function correctly caps the copy_from_user size with min(size, sizeof(crxnfc)), ensuring the copy never exceeds the stack-allocated destination buffer. The scanner flagged the user-controlled 'size' parameter, but the min() operation with sizeof(crxnfc) is precisely the correct and sufficient guard. No counterexample can be constructed where the copy exceeds the destination buffer.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 874
Taint snippetif (copy_from_user(&crxnfc, useraddr, min(size, sizeof(crxnfc))))
Tainted varmin(size, sizeof(crxnfc))
Unvalidated sizecopy_from_user() arg 2 line 874 — size min(size, sizeof(crxnfc))
Sink snippetif (copy_from_user(&crxnfc, useraddr, min(size, sizeof(crxnfc))))
Possibly guardedno
Dismissed: The 'size' argument is passed from kernel ioctl dispatch code (not directly read from user memory via get_user). Even treating it as user-controlled, min(size, sizeof(crxnfc)) clamps the copy to exactly the size of the stack-allocated destination buffer. Counterexample test: no value of size can cause OOB because min() guarantees the copy is at most sizeof(crxnfc) bytes. This is a textbook false positive — the scanner sees a variable size argument to copy_from_user but misses that min() with the buffer's own sizeof() is the correct mitigation.

ethtool_rxnfc_copy_from_user() — net/ethtool/ioctl.c FP confidence=high

The 'size' parameter in ethtool_rxnfc_copy_from_user() is not user-supplied — it is a kernel-internal value computed by ethtool_rxnfc_copy_struct(). The two values used are: (1) a compile-time offsetof+sizeof expression for ETHTOOL_GRXFH/SRXFH, and (2) sizeof(*info) for the full structure. Both are kernel-controlled constants derived from struct layout, not from any user-supplied data. The destination buffer 'rxnfc' (type struct ethtool_rxnfc *) is large enough to hold sizeof(*info) bytes by definition. There is no path where a user can influence the 'size' argument passed to copy_from_user().

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 903
Taint snippetif (copy_from_user(rxnfc, useraddr, size))
Tainted varsize
Unvalidated sizecopy_from_user() arg 2 line 903 — size size
Sink snippetif (copy_from_user(rxnfc, useraddr, size))
Possibly guardedno
Dismissed: The scanner flagged 'size' as tainted because copy_from_user() returns data from user space, but 'size' is not read from user space — it is the third argument (the length), which is determined entirely by kernel-internal computation in ethtool_rxnfc_copy_struct(). The two possible values are offsetof(struct ethtool_rxnfc, data)+sizeof(info->data) and sizeof(*info), both compile-time constants bounded by the allocated struct size. No counterexample exists because there is no user-controlled code path that can vary 'size'. This is a false positive from the taint tracker conflating the destination buffer (which receives user data) with the size argument.

ethtool_rxnfc_copy_to_compat() — net/ethtool/ioctl.c FP confidence=high

The `size` parameter passed to `copy_to_user()` is bounded by `min(size, sizeof(crxnfc))`, which ensures it never exceeds the size of the local stack buffer `crxnfc`. The `size` value comes from a kernel-internal path parameter, not directly from user-supplied data in an unchecked manner. The `min()` call is the safety guard: regardless of what `size` is, the actual bytes copied cannot exceed `sizeof(crxnfc)`. The source buffer is a local stack variable (`crxnfc`) fully initialized by the kernel. The scanner misidentifies `min(size, sizeof(crxnfc))` as unvalidated, but the `min()` itself IS the validation — it caps the size at the buffer's actual length. No counterexample can be constructed where `min(size, sizeof(crxnfc))` exceeds `sizeof(crxnfc)` — by definition of `min()`.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 932
Taint snippetif (copy_to_user(useraddr, &crxnfc, min(size, sizeof(crxnfc))))
Tainted varmin(size, sizeof(crxnfc))
Unvalidated sizecopy_to_user() arg 2 line 932 — size min(size, sizeof(crxnfc))
Sink snippetif (copy_to_user(useraddr, &crxnfc, min(size, sizeof(crxnfc))))
Possibly guardedno
Dismissed: The `min(size, sizeof(crxnfc))` expression is itself the bounds check. The size passed to `copy_to_user()` is capped at `sizeof(crxnfc)` (the size of the local stack buffer), so it cannot exceed the buffer. No counterexample exists: for any value of `size`, `min(size, sizeof(crxnfc)) <= sizeof(crxnfc)` always holds. The taint source is also misidentified — `size` is a kernel-internal parameter propagated from `ethtool_rxnfc_copy_to_user()`, not raw user input. This is a false positive from the static analyzer treating `min()` as insufficient when it is precisely sufficient.

ethtool_rxnfc_copy_to_user() — net/ethtool/ioctl.c FP confidence=high

Finding #1: 'size' is kernel-internal (sizeof of a kernel stack struct), not user-controlled. Finding #2: rule_cnt is user-supplied but validated before allocation (KMALLOC_MAX_SIZE / sizeof(u32) check); the copy_to_user uses the post-driver-call rule_cnt which could theoretically differ from pre-call count, but the driver is trusted kernel code. Both findings are effectively false positives from the external attack surface perspective.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 981
Taint snippetret = copy_to_user(useraddr, rxnfc, size);
Tainted varsize
Unvalidated sizecopy_to_user() arg 2 line 981 — size size
Sink snippetret = copy_to_user(useraddr, rxnfc, size);
Possibly guardedno
Dismissed: The 'size' parameter originates from 'info_size = sizeof(info)' in all callers — a compile-time constant bounded by the stack-allocated struct ethtool_rxnfc. Not user-controlled. False positive.

Finding #2 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 989
Taint snippetif (copy_to_user(useraddr, rule_buf,
Tainted varrxnfc->rule_cnt * sizeof(u32)
Unvalidated sizecopy_to_user() arg 2 line 989 — size rxnfc->rule_cnt * sizeof(u32)
Sink snippetif (copy_to_user(useraddr, rule_buf,
Possibly guardedno
Dismissed: rule_cnt is user-supplied but validated at allocation time: only allocated if rule_cnt <= KMALLOC_MAX_SIZE/sizeof(u32), and rule_buf is NULL if 0 or exceeds limit. The copy_to_user uses post-driver rule_cnt which could change, but drivers are trusted. No counterexample exists from untrusted userspace: any user-supplied rule_cnt passes through the allocation guard, ensuring the buffer is large enough for the original count. A driver incorrectly increasing rule_cnt would be a driver bug in trusted code.

ethtool_self_test() — net/ethtool/ioctl.c FP confidence=high

The function correctly overwrites the user-supplied test.len at line 2368 with the kernel-derived test_len from get_sset_count(). The allocation at line 2369 and the copy_to_user at line 2381 both use this kernel-controlled value. The static analyzer incorrectly tracks test.len as user-controlled because the struct was initially populated via copy_from_user, missing the unconditional overwrite at line 2368.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 2381
Taint snippetif (copy_to_user(useraddr, data, array_size(test.len, sizeof(u64))))
Tainted vararray_size(test.len, sizeof(u64))
Unvalidated sizecopy_to_user() arg 2 line 2381 — size array_size(test.len, sizeof(u64))
Sink snippetif (copy_to_user(useraddr, data, array_size(test.len, sizeof(u64))))
Possibly guardedno
Dismissed: test.len is set to test_len (a kernel-internal value from get_sset_count()) at line 2368, unconditionally overwriting the user-supplied value. The copy_to_user at line 2381 therefore uses a kernel-controlled size that exactly matches the kcalloc'd buffer size. No counterexample can be constructed because user input cannot influence test.len at the point of the flagged copy_to_user call.

get_phy_tunable() — net/ethtool/ioctl.c FP confidence=high

tuna.len is user-supplied but validated by ethtool_phy_tunable_valid() before use. The allocation kzalloc(tuna.len) and subsequent copy_to_user(..., tuna.len) are symmetric — no kernel OOB is possible since the buffer is exactly tuna.len bytes. The validator ensures tuna.len matches the expected size for the specific tunable ID, bounding it to small known values.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 3189
Taint snippetif (copy_to_user(useraddr, data, tuna.len))
Tainted vartuna.len
Unvalidated sizecopy_to_user() arg 2 line 3189 — size tuna.len
Sink snippetif (copy_to_user(useraddr, data, tuna.len))
Possibly guardedno
Dismissed: ethtool_phy_tunable_valid() validates tuna.len against the expected size for the tunable type before the allocation and copy. The kernel buffer 'data' is allocated to exactly tuna.len bytes, so copy_to_user(useraddr, data, tuna.len) cannot read beyond the allocated buffer. No counterexample exists: any tuna.len that passes validation is a small fixed constant, and data is allocated to that same size. False positive.

dgram_getsockopt() — net/ieee802154/socket.c FP confidence=high

The 'len' variable is user-supplied (via get_user) but is immediately clamped by min_t(unsigned int, len, sizeof(int)) on line 847. sizeof(int) is 4. So len is guaranteed to be in [0, 4] before it reaches copy_to_user. The destination buffer &val is an int on the stack (4 bytes), so copying at most 4 bytes into it is safe. The scanner missed the min_t clamp as a sufficient guard.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 876
Taint snippetif (copy_to_user(optval, &val, len))
Tainted varlen
Unvalidated sizecopy_to_user() arg 2 line 876 — size len
Sink snippetif (copy_to_user(optval, &val, len))
Possibly guardedno
Dismissed: len is read from userspace via get_user, making it user-controlled. However, line 847 clamps it: len = min_t(unsigned int, len, sizeof(int)), so len is in [0, 4]. The copy_to_user call copies at most 4 bytes from &val (a local int, 4 bytes). No counterexample exists: any user-supplied len value, after the clamp, cannot exceed sizeof(int)=4, which is exactly the size of val. The finding is a false positive.

cipso_v4_map_cat_enum_ntoh() — net/ipv4/cipso_ipv4.c FP confidence=high

cipso_v4_map_cat_enum_ntoh() reads category bits from a network packet and passes them to netlbl_catmap_setbit(). While the value is genuinely network-supplied, netlbl_catmap_setbit() is specifically designed to accept any u32 bit position: _netlbl_catmap_getnode() with _CM_F_ALLOC allocates catmap nodes as needed, ensuring the returned node's startbit aligns such that bit-startbit is always within NETLBL_CATMAP_SIZE bounds. No counterexample can be constructed — the catmap API safely handles the full u16 range (0-65535).

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

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_be16() line 982
Taint snippetret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
Tainted varget_unaligned_be16(&net_cat[iter])
Call siteline 982 — passes get_unaligned_be16(&net_cat[iter]) to netlbl_catmap_setbit()
Call snippetret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
Subscript (in callee)[] line 788
Sink snippetiter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE);
Possibly guardedno
Dismissed: netlbl_catmap_setbit() is a purpose-built API for setting arbitrary bit positions in a sparse bitmap structure. It internally calls _netlbl_catmap_getnode(_CM_F_ALLOC) which allocates and links catmap nodes as needed, setting startbit appropriately so that bit-startbit always falls within the node's bitmap[] array bounds. No OOB is possible regardless of the input u16 category value. The scanner flagged the bitmap[] subscript as a sink, but that subscript is bounded by the catmap node allocation logic. This is a false positive.

cipso_v4_map_cat_rng_ntoh() — net/ipv4/cipso_ipv4.c FP confidence=high

The scanner flagged cat_low and cat_high (network-supplied u16 values) as controlling a 'dangerous loop bound' in netlbl_catmap_setrng(). However, that loop does not index a fixed-size buffer — it iterates through a logical category range and dynamically allocates catmap bitmap nodes via netlbl_catmap_setbit()/netlbl_catmap_setlong(). The u16 values are inherently bounded to [0, 65535], preventing integer overflow. If cat_low > cat_high (start > end), the while loop condition 'spot <= end' is immediately false, so no iterations occur. The catmap structure grows dynamically as needed, making this safe for any u16 range. At most this represents a theoretical DoS (large range → many small allocations), not an OOB memory vulnerability.

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

CategoryCat F — server value → loop iteration count
Taint sourceget_unaligned_be16() line 1118
Taint snippetcat_low = get_unaligned_be16(&net_cat[net_iter + 2]);
Tainted varcat_low
Call siteline 1122 — passes cat_low to netlbl_catmap_setrng()
Call snippetret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat,
Loopwhile_loop line 814
Sink snippetwhile (rc == 0 && spot <= end) {
Possibly guardedno
Dismissed: cat_low is a network-supplied u16 value passed as 'start' to netlbl_catmap_setrng(). The function iterates from start to end setting bits in a dynamically allocated catmap structure — no fixed-size buffer is indexed. No counterexample exists that causes OOB access: any u16 value (0-65535) is safe because the catmap allocates nodes dynamically. False positive.

Finding #2 — Category F — cross-function via netlbl_catmap_setrng() — false positive

CategoryCat F — server value → loop iteration count
Taint sourceget_unaligned_be16() line 1116
Taint snippetcat_high = get_unaligned_be16(&net_cat[net_iter]);
Tainted varcat_high
Call siteline 1122 — passes cat_high to netlbl_catmap_setrng()
Call snippetret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat,
Loopwhile_loop line 814
Sink snippetwhile (rc == 0 && spot <= end) {
Possibly guardedno
Dismissed: cat_high is a network-supplied u16 value passed as 'end' to netlbl_catmap_setrng(). Same analysis as finding #1: the loop in netlbl_catmap_setrng() dynamically allocates catmap nodes for any range, so no OOB access is possible. If cat_high < cat_low (end < start), the loop exits immediately. If cat_high = 65535 (maximum u16), the loop may iterate many times but only performs safe dynamic allocations. False positive.

rtentry_to_fib_config() — net/ipv4/fib_frontend.c FP confidence=high

The scanner misidentified the size argument IFNAMSIZ-1 as user-controlled/tainted. IFNAMSIZ is a compile-time kernel constant (16), so IFNAMSIZ-1 is a fixed value 15. The copy_from_user() call copies at most 15 bytes into a devname[IFNAMSIZ] (16-byte) buffer, which is perfectly safe. The source pointer rt->rt_dev is user-supplied, but the size is entirely kernel-controlled. This is a textbook false positive from the taint analysis conflating the source pointer taint with the size argument.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 542
Taint snippetif (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1))
Tainted varIFNAMSIZ-1
Unvalidated sizecopy_from_user() arg 2 line 542 — size IFNAMSIZ-1
Sink snippetif (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1))
Possibly guardedno
Dismissed: IFNAMSIZ is a kernel compile-time constant (#define IFNAMSIZ 16), so IFNAMSIZ-1 equals 15 — a fixed, kernel-internal value that is not user-controlled in any way. The destination buffer devname[IFNAMSIZ] has 16 bytes of capacity, so copying IFNAMSIZ-1=15 bytes is always safe and cannot overflow. The scanner appears to have propagated taint from rt->rt_dev (the user-supplied source pointer) onto the size argument, which is incorrect — the size is not derived from any user-supplied value. No counterexample exists where this causes OOB access, confirming this is a false positive.

fib_table_insert() — net/ipv4/fib_trie.c FP confidence=high

The function handles routing table insertion with kernel-internal data structures. The fib_alias fields are maintained by the kernel, not populated from network packets. The scanner incorrectly propagated ntohl() taint through unrelated internal struct fields.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 1283
Taint snippetstate = READ_ONCE(fa->fa_state);
Tainted varstate
Truncationline 1283: 32 → 8-bit u8
Sink snippetstate = READ_ONCE(fa->fa_state);
Possibly guardedyes (heuristic)
Dismissed: fa->fa_state is a u8 field in struct fib_alias, which is a kernel-internal routing table data structure — not a network-received buffer. The READ_ONCE() reads a u8 into a u8 local variable (state is declared u8 on line 1265), so there is no truncation at all. The scanner incorrectly propagated ntohl() taint (from network address processing) through internal struct fields via alias lookup. No counterexample can be constructed because the source and destination types are identical (u8), making truncation impossible.

fib_table_lookup() — net/ipv4/fib_trie.c FP confidence=high

The trie lookup function uses the network-supplied destination address (key) to index into trie nodes. While the key is technically tainted, the trie data structure maintains the invariant that each node's child array has exactly 1<<bits entries and that get_index(pkey, pn) returns a value in [0, 1<<pn->bits) due to how parent-child relationships are established during trie construction. The cindex &= cindex-1 operation at line 1537 only decreases the value. The bounds check at line 1464 ensures index < (1<<n->bits) during forward traversal, establishing trie structural invariants. The use at line 1540 is protected by these invariants — no concrete counterexample exists where cindex could exceed pn->tnode array bounds without violating trie structural invariants established at node insertion time.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 1427
Taint snippetconst t_key key = ntohl(flp->daddr);
Tainted varcindex
Subscript[] line 1540
Sink snippetcptr = &pn->tnode[cindex];
Possibly guardedno
Dismissed: The key (from ntohl(flp->daddr)) flows into cindex through get_index() which computes (key ^ pn->key) >> pn->pos. The trie structural invariant guarantees this result fits within pn->bits bits (i.e., is < 1<<pn->bits), because parent-child relationships in the trie are established such that the bits at positions [pos, pos+bits) uniquely identify the child. The operation cindex &= cindex-1 at line 1537 clears the LSB, making the value strictly smaller — so if cindex was in-bounds before, it remains in-bounds. No counterexample can be constructed: any cindex value ≥ 1<<pn->bits would require a corrupted trie node, not merely a crafted key. This is a false positive from the static analyzer not understanding trie structural invariants.

icmp_build_probe() — net/ipv4/icmp.c FP confidence=high

The function has solid validation discipline. ident_len is derived from network data but is bounded by the check at lines 1324-1326 (must be > 0 and <= sizeof(_iio) - sizeof(iio->extobj_hdr)). The second skb_header_pointer call at line 1328 copies exactly sizeof(iio->extobj_hdr)+ident_len bytes into the stack buffer _iio, so all subsequent iio->* accesses are within a locally-held stack buffer. Per-case ident_len checks (IFNAMSIZ, sizeof(ifindex), sizeof(ctype3_hdr)+addrlen) provide additional validation. dev/in_dev/in6_dev are kernel-internal struct pointers from device lookups, not derived from packet offsets.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->extobj_hdr line 1329
Sink snippetsizeof(iio->extobj_hdr) + ident_len, &_iio);
Possibly guardedno
Dismissed: iio points to stack buffer _iio after skb_header_pointer at line 1328. ident_len is bounded to [1, sizeof(_iio)-sizeof(extobj_hdr)] by the check at lines 1324-1326. No counterexample possible: ident_len cannot exceed sizeof(_iio)-sizeof(extobj_hdr), so the copy into _iio is always within bounds.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->extobj_hdr line 1335
Sink snippetswitch (iio->extobj_hdr.class_type) {
Possibly guardedno
Dismissed: iio->extobj_hdr.class_type at line 1335: iio points to _iio stack buffer. The buffer was filled by skb_header_pointer with exactly sizeof(extobj_hdr)+ident_len bytes, all within sizeof(_iio). Access is safe.

Finding #3 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted varident_len
Sinkmemcpy() line 1340 (arg 2, role=size)
Sink snippetmemcpy(buff, &iio->ident.name, ident_len);
Possibly guardedyes (heuristic)
Dismissed: ident_len is checked < IFNAMSIZ at line 1337 (destination bound) and is bounded by sizeof(_iio)-sizeof(extobj_hdr) (source bound via skb_header_pointer). No counterexample: ident_len must be < IFNAMSIZ to reach memcpy, and buff is IFNAMSIZ bytes. Both OOB read and OOB write are prevented.

Finding #4 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Sinkmemcpy() line 1340 (arg 1, role=pointer)
Sink snippetmemcpy(buff, &iio->ident.name, ident_len);
Possibly guardedno
Dismissed: &iio->ident.name is within the _iio stack buffer. skb_header_pointer validated that the packet contained enough data and copied it into _iio. ident_len < IFNAMSIZ ensures no OOB read of _iio.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1340
Sink snippetmemcpy(buff, &iio->ident.name, ident_len);
Possibly guardedno
Dismissed: Same as #4. iio->ident is within _iio stack buffer. ident_len < IFNAMSIZ guard at line 1337 ensures the name field is within bounds.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1344
Sink snippetif (ident_len != sizeof(iio->ident.ifindex))
Possibly guardedno
Dismissed: sizeof(iio->ident.ifindex) is a compile-time constant used for comparison only. iio points to _iio stack buffer. Access is safe.

Finding #7 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1346
Sink snippetdev = dev_get_by_index(net, ntohl(iio->ident.ifindex));
Possibly guardedyes (heuristic)
Dismissed: Line 1344 checks ident_len == sizeof(iio->ident.ifindex), so ifindex is within the validated _iio buffer. dev_get_by_index receives an integer value, not a raw packet pointer. False positive.

Finding #8 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1349
Sink snippetif (ident_len < sizeof(iio->ident.addr.ctype3_hdr) ||
Possibly guardedyes (heuristic)
Dismissed: Lines 1349-1352 validate ident_len >= sizeof(ctype3_hdr) and exactly equals sizeof(ctype3_hdr)+addrlen. iio is in _iio stack buffer. Access is safe.

Finding #9 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1350
Sink snippetident_len != sizeof(iio->ident.addr.ctype3_hdr) +
Possibly guardedyes (heuristic)
Dismissed: Same guard as #8. False positive.

Finding #10 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1351
Sink snippetiio->ident.addr.ctype3_hdr.addrlen)
Possibly guardedyes (heuristic)
Dismissed: addrlen is read from _iio stack buffer at line 1351 for comparison only (not used as a size for allocation or copy). The ctype3_hdr is within the validated buffer. False positive.

Finding #11 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1353
Sink snippetswitch (ntohs(iio->ident.addr.ctype3_hdr.afi)) {
Possibly guardedyes (heuristic)
Dismissed: ntohs(iio->ident.addr.ctype3_hdr.afi) is read from _iio stack buffer after validation. Used only as a switch discriminant. False positive.

Finding #12 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1355
Sink snippetif (iio->ident.addr.ctype3_hdr.addrlen != sizeof(struct in_addr))
Possibly guardedyes (heuristic)
Dismissed: addrlen compared against sizeof(struct in_addr) — a compile-time constant. No memory operation sized by this. False positive.

Finding #13 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1357
Sink snippetdev = ip_dev_find(net, iio->ident.addr.ip_addr.ipv4_addr);
Possibly guardedyes (heuristic)
Dismissed: ip_dev_find receives a 4-byte IPv4 address from _iio stack buffer. addrlen was validated == sizeof(struct in_addr) at line 1355. ip_addr.ipv4_addr is within the validated buffer. False positive.

Finding #14 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1361
Sink snippetif (iio->ident.addr.ctype3_hdr.addrlen != sizeof(struct in6_addr))
Possibly guardedyes (heuristic)
Dismissed: addrlen compared against sizeof(struct in6_addr). Access to _iio stack buffer within bounds. False positive.

Finding #15 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted variio
Pointer derefiio->ident line 1363
Sink snippetdev = ipv6_dev_find(net, &iio->ident.addr.ip_addr.ipv6_addr, dev);
Possibly guardedyes (heuristic)
Dismissed: ipv6_dev_find receives pointer to in6_addr within _iio stack buffer. addrlen validated == sizeof(struct in6_addr) at line 1361. False positive.

Finding #16 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted vardev
Pointer derefdev->flags line 1379
Sink snippetif (dev->flags & IFF_UP)
Possibly guardedno
Dismissed: dev is a kernel-internal net_device pointer returned by dev_get_by_name/dev_get_by_index/ip_dev_find/ipv6_dev_find. It is not derived from packet offset arithmetic. The taint propagation to dev->flags is a false positive from over-approximation in the static analyzer.

Finding #17 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted varin_dev
Pointer derefin_dev->ifa_list line 1383
Sink snippetif (in_dev && rcu_access_pointer(in_dev->ifa_list))
Possibly guardedno
Dismissed: in_dev is obtained via __in_dev_get_rcu(dev) where dev is a kernel net_device pointer. Not derived from packet data. False positive from taint over-approximation.

Finding #18 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1327
Taint snippetident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
Tainted varin6_dev
Pointer derefin6_dev->addr_list line 1387
Sink snippetif (in6_dev && !list_empty(&in6_dev->addr_list))
Possibly guardedno
Dismissed: in6_dev is obtained via __in6_dev_get(dev) where dev is a kernel net_device pointer. Not derived from packet data. False positive from taint over-approximation.

igmp_heard_query() — net/ipv4/igmp.c FP confidence=high

igmp_heard_query() has proper v3 path validation: pskb_may_pull() is called with sizeof(igmpv3_query) + ntohs(ih3->nsrcs)*sizeof(__be32) before ih3 is re-derived and nsrcs is used. This guarantees the srcs array in the packet has sufficient contiguous bytes for the loop in igmp_marksources(). The static analysis flagged a network-supplied loop bound, but the bounds check is present and sufficient.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1093
Taint snippetigmp_marksources(im, ntohs(ih3->nsrcs), ih3->srcs);
Tainted varntohs(ih3->nsrcs)
Call siteline 1093 — passes ntohs(ih3->nsrcs) to igmp_marksources()
Call snippetigmp_marksources(im, ntohs(ih3->nsrcs), ih3->srcs);
Loopfor_loop line 933
Sink snippetfor (i = 0; i < nsrcs; i++)
Possibly guardedyes (heuristic)
Dismissed: The pskb_may_pull() at lines 1030-1032 validates that the skb contains sizeof(igmpv3_query) + ntohs(ih3->nsrcs)*sizeof(__be32) contiguous bytes. After this check passes and ih3 is re-derived at line 1033, accessing srcs[i] for i in [0, nsrcs) is safe because the buffer is guaranteed to hold all nsrcs source addresses. No counterexample can be constructed: any nsrcs value that passes pskb_may_pull() has sufficient backing data for the loop. False positive.

tcp_v4_early_demux() — net/ipv4/ip_input.c FP confidence=high

tcp_v4_early_demux() properly validates the TCP header presence and minimum doff before use. The network-supplied port value flows into __inet_lookup_established(), but the array subscript is computed as 'hash & hashinfo->ehash_mask', which is a power-of-2 mask bounding the slot to the valid array range regardless of any input value. This is the standard Linux hash table lookup pattern and is not exploitable.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 342
Taint snippetsk = __inet_lookup_established(net, iph->saddr, th->source,
Tainted varntohs(th->dest)
Call siteline 342 — passes ntohs(th->dest) to __inet_lookup_established()
Call snippetsk = __inet_lookup_established(net, iph->saddr, th->source,
Subscript (in callee)[] line 546
Sink snippethead = &hashinfo->ehash[slot];
Possibly guardedno
Dismissed: The array subscript 'slot = hash & hashinfo->ehash_mask' applies a bitmask that unconditionally bounds the index to [0, ehash_mask], which equals [0, ehash_size-1]. No counterexample exists: any value of ntohs(th->dest) fed through inet_ehashfn() and then ANDed with ehash_mask produces a valid array index. The scanner incorrectly flagged this standard masked-hash-table-lookup pattern as a potential OOB access.

ic_bootp_recv() — net/ipv4/ipconfig.c FP confidence=medium

The function has a solid validation chain: skb->len >= ntohs(h->tot_len) at line 1019, pskb_may_pull linearizing the full skb at line 1040, and ext_len >= 0 check. The 'end' pointer is therefore bounded to within the actual packet buffer. Both loops use 'ext < end' as their condition, preventing reads past end. The per-option length field (*ext) controls advancement within the loop, but both loops check 'if (ext >= end) break' (finding #1) or 'if (ext < end)' (finding #2) after advancement, so no dereference occurs past end. The real concern would be opt[1]/opt[2] accesses near the boundary, but these are bounded by the same end pointer checks.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1071
Taint snippetu8 *end = (u8 *) b + ntohs(b->iph.tot_len);
Tainted varend
Loopwhile_loop line 1080
Sink snippetwhile (ext < end && *ext != 0xff) {
Possibly guardedno
Dismissed: The 'end' pointer is derived from ntohs(b->iph.tot_len), which is validated at line 1019 to be <= skb->len, and pskb_may_pull at line 1040 ensures the full skb is linearized. So 'end' does not exceed the actual buffer. The loop at line 1080 checks 'ext < end' before dereferencing *ext, and checks 'if (ext >= end) break' after advancing. Could not construct a counterexample where a valid packet causes OOB: any tot_len large enough to move end past the buffer is caught by line 1019.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1071
Taint snippetu8 *end = (u8 *) b + ntohs(b->iph.tot_len);
Tainted varend
Loopwhile_loop line 1143
Sink snippetwhile (ext < end && *ext != 0xff) {
Possibly guardedyes (heuristic)
Dismissed: Same analysis as finding #1. The loop at line 1143 checks 'ext < end' before dereferencing, and 'if (ext < end)' guards the ic_do_bootp_ext call. The 'end' boundary is itself validated against the actual buffer via line 1019 + pskb_may_pull. No counterexample could be constructed.

__do_replace() — net/ipv4/netfilter/arp_tables.c FP confidence=high

The `num_counters` value originates from user space (via `tmp.num_counters` in the calling functions), but both call sites validate it before passing it to `__do_replace()`. Specifically, both `do_replace()` and `compat_do_replace()` check: (1) `tmp.num_counters >= INT_MAX / sizeof(struct xt_counters)` → return -ENOMEM (overflow guard), and (2) `tmp.num_counters == 0` → return -EINVAL. The `counters` buffer is allocated via `xt_counters_alloc(num_counters)` inside `__do_replace()`, which allocates exactly `num_counters * sizeof(struct xt_counters)` bytes. The subsequent `copy_to_user()` call copies exactly `sizeof(struct xt_counters) * num_counters` bytes from that same buffer. Since the allocation size matches the copy size and the overflow check is done before the call, the copy cannot exceed the allocated buffer. No counterexample exists: any value that passes the overflow guard and non-zero check will result in a properly sized allocation that matches the copy size.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 944
Taint snippetif (copy_to_user(counters_ptr, counters,
Tainted varsizeof(struct xt_counters) * num_counters
Unvalidated sizecopy_to_user() arg 2 line 944 — size sizeof(struct xt_counters) * num_counters
Sink snippetif (copy_to_user(counters_ptr, counters,
Possibly guardedno
Dismissed: Both call sites perform: (1) overflow check `num_counters >= INT_MAX / sizeof(struct xt_counters)` preventing multiplication overflow, and (2) zero check `num_counters == 0`. Inside `__do_replace()`, `xt_counters_alloc(num_counters)` allocates exactly `num_counters * sizeof(struct xt_counters)` bytes. The `copy_to_user()` at line 944 copies the same quantity. Since allocation size equals copy size and the overflow is precluded, no OOB write is possible. Counterexample attempt: to pass the guards, `num_counters` must be in range [1, INT_MAX/sizeof(xt_counters)-1]. For any such value, allocation matches copy size. No counterexample found.

__do_replace() — net/ipv4/netfilter/ip_tables.c FP confidence=high

The num_counters value is user-supplied (from tmp.num_counters read via copy_from_sockptr), but both call sites validate it before calling __do_replace(). Specifically: (1) tmp.num_counters == 0 is rejected, (2) tmp.num_counters >= INT_MAX / sizeof(struct xt_counters) is rejected (overflow check), and (3) xt_counters_alloc(num_counters) at line 1044 allocates exactly num_counters * sizeof(struct xt_counters) bytes. The copy_to_user at line 1083 copies sizeof(struct xt_counters) * num_counters bytes from the counters buffer, which was allocated with exactly that size. No counterexample can be constructed: any value that passes the overflow check and non-zero check results in a correctly-sized allocation, and the copy_to_user uses the same count. The finding is a false positive.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 1083
Taint snippetif (copy_to_user(counters_ptr, counters,
Tainted varsizeof(struct xt_counters) * num_counters
Unvalidated sizecopy_to_user() arg 2 line 1083 — size sizeof(struct xt_counters) * num_counters
Sink snippetif (copy_to_user(counters_ptr, counters,
Possibly guardedno
Dismissed: num_counters is user-supplied but validated at both call sites: zero is rejected, and overflow (num_counters >= INT_MAX / sizeof(struct xt_counters)) is rejected. xt_counters_alloc() allocates exactly num_counters * sizeof(struct xt_counters) bytes. The copy_to_user uses the identical expression as the allocation, so the copy never exceeds the allocated buffer. No counterexample exists where a value passes all guards yet causes OOB — the allocation and copy use the same count, and the count is bounded by INT_MAX / sizeof(struct xt_counters).

pptp_inbound_pkt() — net/ipv4/netfilter/nf_nat_pptp.c FP confidence=high

The pptp_msg_name() function explicitly validates its argument before using it as an array subscript. The check 'if (msg > PPTP_MSG_MAX) return pptp_msg_name_array[0]' ensures that only values <= PPTP_MSG_MAX are used as subscripts. Any out-of-range value returns the safe index 0. This is a classic validation-function pattern — the internal array access IS the validated path, not a vulnerable sink.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 256
Taint snippetswitch (msg = ntohs(ctlh->messageType)) {
Tainted varmsg
Call siteline 276 — passes msg to pptp_msg_name()
Call snippetpr_debug("unknown inbound packet %s\n", pptp_msg_name(msg));
Subscript (in callee)[] line 77
Sink snippetreturn pptp_msg_name_array[msg];
Possibly guardedyes (heuristic)
Dismissed: pptp_msg_name() checks 'if (msg > PPTP_MSG_MAX) return pptp_msg_name_array[0]' before using msg as a subscript. No counterexample exists: any msg value either returns index 0 (safe) or returns pptp_msg_name_array[msg] where msg <= PPTP_MSG_MAX (also safe). The callee itself is the validation + safe access function. False positive.

pptp_outbound_pkt() — net/ipv4/netfilter/nf_nat_pptp.c FP confidence=high

The flagged flow involves msg (from ntohs(ctlh->messageType)) being passed to pptp_msg_name(). The callee pptp_msg_name() explicitly checks 'if (msg > PPTP_MSG_MAX) return pptp_msg_name_array[0];' before indexing the array. This is a complete and sufficient bounds check internal to the callee. No counterexample can be constructed: any msg > PPTP_MSG_MAX returns the safe [0] element, and any msg <= PPTP_MSG_MAX is a valid index. The function is a validation/name-lookup helper that guards its own parameter.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 147
Taint snippetswitch (msg = ntohs(ctlh->messageType)) {
Tainted varmsg
Call siteline 173 — passes msg to pptp_msg_name()
Call snippetpptp_msg_name(msg));
Subscript (in callee)[] line 77
Sink snippetreturn pptp_msg_name_array[msg];
Possibly guardedyes (heuristic)
Dismissed: pptp_msg_name() validates its argument with 'if (msg > PPTP_MSG_MAX) return pptp_msg_name_array[0];' before the array subscript at line 77. No value of msg (u_int16_t, 0..65535) can cause OOB access: values above PPTP_MSG_MAX return the safe [0] element, values at or below PPTP_MSG_MAX are valid indices. Cannot construct a counterexample that passes the guard yet causes OOB. This is a false positive — the callee performs its own internal bounds check.
The scanner flagged mssind as tainted and used as an array subscript without a bounds check, but missed the explicit bounds check on line 193. The ternary expression `mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0` is a textbook bounds-checked array access. Furthermore, check_tcp_syn_cookie() returns ((__u32)-1) = 0xFFFFFFFF if the cookie fails age validation, which will fail the `< ARRAY_SIZE(msstab)` test and return 0 safely. The COOKIEMASK further limits the return value to low bits. No counterexample can be constructed that passes the guard yet causes OOB access.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 186
Taint snippet__u32 cookie = ntohl(th->ack_seq) - 1;
Tainted varmssind
Subscript[] line 193
Sink snippetreturn mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
Possibly guardedno
Dismissed: The ternary on line 193 is `mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0` — this IS a proper bounds check. The scanner apparently marked it as 'possibly guarded: no', which is incorrect; the guard is directly in the same expression as the sink. check_tcp_syn_cookie() returns 0xFFFFFFFF on failure (which fails the bounds check) or a value masked by COOKIEMASK (which limits it to a small number of bits). No counterexample exists: any value >= ARRAY_SIZE(msstab) returns 0, any value < ARRAY_SIZE(msstab) is safe to use as a subscript. False positive.

tcp_v4_err() — net/ipv4/tcp_ipv4.c FP confidence=high

The flagged flow traces ntohs(th->source) through __inet_lookup_established() to a hash table array subscript. The key insight is that the 'slot' used as the subscript is computed as 'hash & hashinfo->ehash_mask', which is a bitmask operation that inherently bounds the result to valid indices of the ehash array (ehash_mask is set to ehash_size-1 at allocation time). The ntohs() value is merely one input to inet_ehashfn() which produces a hash, and the subsequent AND with ehash_mask makes OOB access impossible regardless of the input value. This is standard hash table indexing in the Linux kernel and is not a vulnerability.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 504
Taint snippetsk = __inet_lookup_established(net, iph->daddr, th->dest, iph->saddr,
Tainted varntohs(th->source)
Call siteline 504 — passes ntohs(th->source) to __inet_lookup_established()
Call snippetsk = __inet_lookup_established(net, iph->daddr, th->dest, iph->saddr,
Subscript (in callee)[] line 546
Sink snippethead = &hashinfo->ehash[slot];
Possibly guardedno
Dismissed: The tainted value ntohs(th->source) is genuinely network-supplied (from the TCP header of an ICMP error payload). However, inside __inet_lookup_established(), the value is passed to inet_ehashfn() which produces a cryptographic/hash output, and then 'slot = hash & hashinfo->ehash_mask' bounds the result to [0, ehash_mask]. Since ehash_mask == ehash_size - 1 (a power-of-two minus one), the AND operation guarantees slot is always a valid index into hashinfo->ehash[]. No counterexample exists where a network-supplied port value could cause slot >= ehash_size, because the bitmask is an absolute bound. This is the standard Linux kernel hash table indexing pattern and is safe by design.

tcp4_check_fraglist_gro() — net/ipv4/tcp_offload.c FP confidence=high

The tainted network-supplied port value (ntohs(th->dest)) is used as input to inet_ehashfn(), a hash function. The result is then masked with ehash_mask before use as an array subscript ('slot = hash & hashinfo->ehash_mask'), which unconditionally bounds the index to valid array positions. This is the standard safe hash table lookup pattern in the Linux kernel. The scanner cannot see through the hash + mask indirection and incorrectly flags the array access as potentially OOB.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 410
Taint snippetsk = __inet_lookup_established(net, iph->saddr, th->source,
Tainted varntohs(th->dest)
Call siteline 410 — passes ntohs(th->dest) to __inet_lookup_established()
Call snippetsk = __inet_lookup_established(net, iph->saddr, th->source,
Subscript (in callee)[] line 546
Sink snippethead = &hashinfo->ehash[slot];
Possibly guardedno
Dismissed: ntohs(th->dest) is network-supplied (u16, range 0–65535), but it is never used directly as an array index. It flows into inet_ehashfn() as one of several inputs to produce a hash value, and the result is then bounded by 'slot = hash & hashinfo->ehash_mask'. The mask operation guarantees slot < ehash array size regardless of any input value. No counterexample is possible: any value of th->dest produces a hash that, after masking, is a valid index. False positive due to taint tracking not modeling the hash+mask bounding pattern.

__udp4_lib_lookup() — net/ipv4/udp.c FP confidence=high

Finding #1 is a false positive because the provided udp4_lib_lookup4() is a stub returning NULL with no array access. Finding #2 is a false positive because udp_hashfn() masks hnum with udptable->mask (hnum & mask), guaranteeing the slot index is always within the allocated hash[] array bounds regardless of the input value.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 672
Taint snippetunsigned short hnum = ntohs(dport);
Tainted varhnum
Call siteline 681 — passes hnum to udp4_lib_lookup4()
Call snippetresult = udp4_lib_lookup4(net, saddr, sport, daddr, hnum,
Subscript (in callee)[] line 549
Sink snippethslot4 = &udptable->hash4[slot];
Possibly guardedno
Dismissed: The provided callee source for udp4_lib_lookup4() is a stub that returns NULL unconditionally (line 522). There is no array subscript operation in the callee as provided. The scanner's reference to line 549 does not match the included source. This is a false positive — the scanner may have analyzed a different version or a different configuration of this function.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 672
Taint snippetunsigned short hnum = ntohs(dport);
Tainted varhnum
Call siteline 726 — passes hnum to udp4_lib_lookup1()
Call snippetresult = udp4_lib_lookup1(net, saddr, sport, daddr, hnum, dif, sdif,
Subscript (in callee)[] line 441
Sink snippetstruct udp_hslot *hslot = &udptable->hash[slot];
Possibly guardedno
Dismissed: Inside udp4_lib_lookup1(), hnum is passed to udp_hashfn(net, hnum, udptable->mask) which computes hnum & udptable->mask. The resulting slot is always in the range [0, mask], and the hash[] array has mask+1 entries. No counterexample exists: for any 16-bit hnum value, slot = hnum & mask <= mask, which is within bounds. The masking operation is a complete and sufficient bounds constraint.

__udp4_lib_mcast_deliver() — net/ipv4/udp.c FP confidence=high

The function correctly bounds hash2 via '& udptable->mask' before using it as an array index. The mask is set to (hash2_table_size - 1), so the bitwise AND guarantees hash2 < hash2_table_size, making the array access safe. The static analyzer tracked taint from ntohs() through ipv4_portaddr_hash() but failed to recognize the masking operation as a sufficient bounds check.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 2470
Taint snippetunsigned short hnum = ntohs(uh->dest);
Tainted varhash2
Subscript[] line 2490
Sink snippethslot = &udptable->hash2[hash2].hslot;
Possibly guardedno
Dismissed: hash2 is computed as 'ipv4_portaddr_hash(net, daddr, hnum) & udptable->mask'. The mask is (hash2_table_size - 1) for a power-of-two sized table, so hash2 is always in [0, mask], which is exactly the valid index range for udptable->hash2[]. No counterexample is constructible: any value of hnum/daddr after masking will produce an in-bounds index. This is the standard Linux hashtable lookup pattern and the finding is a false positive from the static analyzer not modeling bitwise-AND as a bounds constraint.

__udp4_lib_mcast_demux_lookup() — net/ipv4/udp.c FP confidence=high

The slot value is computed by udp_hashfn() which applies '& mask' (where mask = hash_size - 1), guaranteeing the result is always a valid index into udptable->hash[]. This is a standard power-of-two hash table indexing pattern that provides inherent bounds safety regardless of the input port value.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 2705
Taint snippetunsigned short hnum = ntohs(loc_port);
Tainted varslot
Subscript[] line 2711
Sink snippethslot = &udptable->hash[slot];
Possibly guardedno
Dismissed: Although loc_port is network-supplied, the array index is computed as udp_hashfn(net, hnum, udptable->mask) which internally performs '(hnum + net_hash_mix(net)) & mask'. The bitwise AND with mask (= hash_size - 1) clamps the result to [0, hash_size-1], exactly the valid range of udptable->hash[]. No counterexample exists: any value of hnum, after being ANDed with mask, must be <= mask < hash_size. The static scanner missed this implicit bounds guarantee embedded in the hash function.

esp6_find_tcp_sk() — net/ipv6/esp6.c FP confidence=high

The taint source (encap->encap_sport) is from an XFRM state configured via local netlink, not a server-supplied network packet. More importantly, the flagged sink uses slot = hash & hashinfo->ehash_mask, which is a standard hashtable masking operation that unconditionally constrains the array index to valid bounds regardless of the input port value. No counterexample exists that would cause OOB access.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 155
Taint snippetsk = __inet6_lookup_established(net, &x->id.daddr.in6, dport,
Tainted varntohs(sport)
Call siteline 155 — passes ntohs(sport) to __inet6_lookup_established()
Call snippetsk = __inet6_lookup_established(net, &x->id.daddr.in6, dport,
Subscript (in callee)[] line 101
Sink snippethead = &hashinfo->ehash[slot];
Possibly guardedno
Dismissed: sport is from x->encap (kernel-internal XFRM state, configured via privileged netlink), not a server network response. The array subscript 'slot = hash & hashinfo->ehash_mask' masks with ehash_mask which equals ehash_size-1 (power-of-2 bound), making it impossible for slot to exceed array bounds regardless of port value. No counterexample can be constructed. This is a standard safe hashtable lookup pattern; the scanner is flagging a false positive on the hash&mask idiom.

tcp_v6_early_demux() — net/ipv6/ip6_input.c FP confidence=high

tcp_v6_early_demux() performs appropriate header validation (pskb_may_pull, doff check) before extracting TCP header fields. The flagged cross-function 'array subscript' sink in __inet6_lookup_established() is fully protected by the hash masking operation: slot = hash & hashinfo->ehash_mask always produces a valid index within the ehash array, regardless of the network-supplied port value. This is a standard, correct hash-table lookup pattern throughout the Linux kernel.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 70
Taint snippetsk = __inet6_lookup_established(net, &hdr->saddr, th->source,
Tainted varntohs(th->dest)
Call siteline 70 — passes ntohs(th->dest) to __inet6_lookup_established()
Call snippetsk = __inet6_lookup_established(net, &hdr->saddr, th->source,
Subscript (in callee)[] line 101
Sink snippethead = &hashinfo->ehash[slot];
Possibly guardedno
Dismissed: The tainted value ntohs(th->dest) is a network-supplied port number (genuinely external). However, inside __inet6_lookup_established(), it is passed through inet6_ehashfn() to produce a hash, then masked with 'hash & hashinfo->ehash_mask' before use as an array index. Since ehash is allocated with ehash_mask+1 entries, the mask operation unconditionally constrains slot to [0, ehash_mask]. No counterexample exists: any u16 port value, after hashing and masking, yields a valid in-bounds slot. The scanner flagged a taint flow to an array subscript without recognizing that the masking operation is the bounds check.

__do_replace() — net/ipv6/netfilter/ip6_tables.c FP confidence=high

num_counters is user-supplied but is validated before __do_replace() is called. Both call sites check: (1) num_counters >= INT_MAX / sizeof(struct xt_counters) — overflow guard, (2) num_counters == 0 — zero guard. The allocation at line 1061 uses xt_counters_alloc(num_counters) which allocates exactly num_counters * sizeof(struct xt_counters) bytes. The copy_to_user at line 1100 copies exactly sizeof(struct xt_counters) * num_counters bytes from that same allocation — so the size matches the allocation size by construction. No counterexample can be constructed: any value that passes the overflow check and non-zero check will produce an allocation at least as large as the copy size.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 1100
Taint snippetif (copy_to_user(counters_ptr, counters,
Tainted varsizeof(struct xt_counters) * num_counters
Unvalidated sizecopy_to_user() arg 2 line 1100 — size sizeof(struct xt_counters) * num_counters
Sink snippetif (copy_to_user(counters_ptr, counters,
Possibly guardedno
Dismissed: num_counters comes from user-supplied struct ip6t_replace/compat_ip6t_replace. Both callers validate: (a) num_counters >= INT_MAX/sizeof(struct xt_counters) → -ENOMEM, and (b) num_counters == 0 → -EINVAL. The counters buffer is allocated via xt_counters_alloc(num_counters) which allocates num_counters * sizeof(struct xt_counters) bytes. The copy_to_user uses the identical expression sizeof(struct xt_counters) * num_counters. Since the allocation and the copy use the same validated num_counters, the copy never exceeds the buffer. No counterexample exists: to overflow the multiplication one would need num_counters >= INT_MAX/sizeof(xt_counters), which is blocked. This is a false positive.

nf_tproxy_get_sock_v6() — net/ipv6/netfilter/nf_tproxy_ipv6.c FP confidence=high

Both findings are false positives. The taint analysis has misidentified the nature of the data and the semantics of the operations involved. Finding #1 misunderstands that 'sk' is a pointer to a kernel socket struct returned by a kernel lookup function — not a pointer derived from a network packet offset. Finding #2 misunderstands that ntohs(dport) is used as a hash input, not a direct array subscript, and that 'slot' is masked by ehash_mask before use.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 96
Taint snippetsk = inet6_lookup_listener(net, skb,
Tainted varsk
Pointer derefsk->sk_refcnt line 102
Sink snippetif (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
Possibly guardedno
Dismissed: The taint source is ntohs() applied to 'dport', which is a __be16 function parameter — but 'sk' is NOT derived from 'dport' via offset arithmetic into a packet buffer. 'sk' is the return value of inet6_lookup_listener(), a kernel internal socket lookup function that returns a pointer to a kernel-managed 'struct sock' object. The access sk->sk_refcnt at line 102 is guarded by 'if (sk && ...)' which ensures sk is non-NULL before dereferencing. This is standard reference-count safe-increment pattern in the kernel. The scanner incorrectly traced 'ntohs()' taint through the lookup call to the returned sk pointer, which is a spurious taint propagation.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 111
Taint snippetsk = __inet6_lookup_established(net, saddr, sport, daddr,
Tainted varntohs(dport)
Call siteline 111 — passes ntohs(dport) to __inet6_lookup_established()
Call snippetsk = __inet6_lookup_established(net, saddr, sport, daddr,
Subscript (in callee)[] line 101
Sink snippethead = &hashinfo->ehash[slot];
Possibly guardedno
Dismissed: ntohs(dport) is a port number (0-65535) passed to __inet6_lookup_established(). Inside that function, it is used as input to inet6_ehashfn() to compute a hash, and the resulting hash is masked by 'hashinfo->ehash_mask' (line 100: slot = hash & hashinfo->ehash_mask) before being used as an array index. The masking operation fully constrains 'slot' to valid indices within the ehash table regardless of the port value. No counterexample exists where a port value in [0, 65535] could cause an out-of-bounds access, because the AND with ehash_mask guarantees slot < table size. This is a standard safe hash-table lookup pattern; the finding is a false positive.

do_rawv6_getsockopt() — net/ipv6/raw.c FP confidence=high

The tainted value 'len' is read from userspace via get_user() at line 1060, making it user-supplied. However, line 1083 clamps it with min_t(unsigned int, sizeof(int), len), which caps it at sizeof(int) == 4 bytes. The destination buffer is &val (a local int on the stack), which is exactly 4 bytes. After the clamp, len cannot exceed 4, so copy_to_user() cannot read beyond &val. No counterexample exists that passes the min_t guard and still causes OOB — the check is both present and sufficient.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 1087
Taint snippetif (copy_to_user(optval, &val, len))
Tainted varlen
Unvalidated sizecopy_to_user() arg 2 line 1087 — size len
Sink snippetif (copy_to_user(optval, &val, len))
Possibly guardedno
Dismissed: len is clamped by min_t(unsigned int, sizeof(int), len) at line 1083 before being used in copy_to_user(). Since sizeof(int)==4 and &val is a local int (4 bytes), any user-supplied len is safely bounded to [0,4]. No counterexample can be constructed: even INT_MAX or a negative value (unsigned comparison forces it >= sizeof(int), so min picks sizeof(int)) results in len==4, which exactly matches the source buffer size. The scanner missed the clamping guard, making this a false positive.

ipip6_tunnel_get_prl() — net/ipv6/sit.c FP confidence=high

The flagged `len` variable in copy_to_user() is not directly user-controlled; it is computed as `sizeof(*kp) * c` where `c` is the actual count of entries written into the kernel-allocated `kp` buffer during the loop. The loop is bounded by `cmax` (derived from user-supplied datalen/sizeof) and by the actual PRL list length. The fallback allocation uses `ca = min(t->prl_count, cmax)`, and since the loop traverses at most `t->prl_count` entries and breaks at `c >= cmax`, `c <= ca` always holds in that path. Thus `len` never exceeds the allocated `kp` buffer size in either allocation path. The copy_to_user destination is in user space (the user's responsibility to provide sufficient space), and no kernel OOB write occurs.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 363
Taint snippetif ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen))
Tainted varlen
Unvalidated sizecopy_to_user() arg 2 line 363 — size len
Sink snippetif ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen))
Possibly guardedno
Dismissed: len = sizeof(*kp) * c, where c is bounded by min(t->prl_count, cmax) due to the loop guard (c >= cmax causes break) and the finite PRL list length. The kp buffer is allocated for max(cmax, ca) entries in the first path and ca=min(t->prl_count,cmax) entries in the fallback path — in both cases len <= allocation size. No counterexample can be constructed where len exceeds the kp buffer. The scanner incorrectly traces datalen taint through the division and min() without recognizing the effective bounding. False positive.
The scanner flagged mssind as tainted from ntohl() and used as an array subscript without bounds check. However, mssind is NOT directly derived from the network-supplied cookie; it is the RETURN VALUE of check_tcp_syn_cookie(), which performs cryptographic verification and returns either a bounded COOKIEMASK-masked value or (__u32)-1 on failure. The line 127 guard 'mssind < ARRAY_SIZE(msstab)' is a proper bounds check: if mssind >= ARRAY_SIZE(msstab) (including the (__u32)-1 failure sentinel), the function returns 0 without indexing the array. No counterexample can be constructed where mssind passes the guard and is out of bounds.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 120
Taint snippet__u32 cookie = ntohl(th->ack_seq) - 1;
Tainted varmssind
Subscript[] line 127
Sink snippetreturn mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
Possibly guardedno
Dismissed: mssind receives its value from check_tcp_syn_cookie(), which either returns (__u32)-1 (0xFFFFFFFF) on age/validity failure or a value masked by COOKIEMASK (low bits of the verified cookie). The ternary guard 'mssind < ARRAY_SIZE(msstab)' at line 127 is a sufficient bounds check: any value >= ARRAY_SIZE(msstab) — including the 0xFFFFFFFF sentinel — causes the expression to evaluate to 0 rather than indexing the array. Counterexample attempt: to pass the guard, mssind must be strictly less than ARRAY_SIZE(msstab), which by definition makes the array access in-bounds. No counterexample exists. False positive.

tcp_v6_err() — net/ipv6/tcp_ipv6.c FP confidence=high

The flagged flow is a standard hash-table lookup pattern in the kernel's TCP socket infrastructure. The value ntohs(th->source) is indeed derived from a network packet, but its use as an array subscript is protected by a hash computation and masking operation. The 'slot' value used as the subscript is computed as 'hash & hashinfo->ehash_mask', where ehash_mask is set to (ehash_size - 1), guaranteeing the slot always falls within bounds of the ehash array. The raw port number is never directly used as an array index — it is fed into inet6_ehashfn() which produces a hash, and that hash is then masked. This is a textbook false positive where the scanner tracks taint through a hash function without recognizing that the mask operation bounds the result.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 417
Taint snippetsk = __inet6_lookup_established(net, &hdr->daddr, th->dest,
Tainted varntohs(th->source)
Call siteline 417 — passes ntohs(th->source) to __inet6_lookup_established()
Call snippetsk = __inet6_lookup_established(net, &hdr->daddr, th->dest,
Subscript (in callee)[] line 101
Sink snippethead = &hashinfo->ehash[slot];
Possibly guardedno
Dismissed: The tainted value ntohs(th->source) is a 16-bit port number read from the incoming ICMP-encapsulated TCP header. However, it is never used directly as an array subscript. Inside __inet6_lookup_established(), the port is passed to inet6_ehashfn() which computes a hash, and then 'slot = hash & hashinfo->ehash_mask' masks the hash to the valid index range. Since ehash_mask = ehash_size - 1 (a bitmask), slot is always in [0, ehash_size-1], making 'hashinfo->ehash[slot]' safe. No counterexample exists: no value of th->source can produce an out-of-bounds slot because the bitwise AND with ehash_mask is a hard upper bound. This is a canonical false positive from taint tracking through a hash+mask pattern.

tcp6_check_fraglist_gro() — net/ipv6/tcpv6_offload.c FP confidence=high

The tainted value ntohs(th->dest) is a network port number extracted from a received TCP header. Inside __inet6_lookup_established(), it is used as the 'hnum' parameter in inet6_ehashfn() to compute a hash, and then 'slot = hash & hashinfo->ehash_mask' masks the hash result before indexing into ehash[slot]. The '& ehash_mask' operation is a classic power-of-two bitmask that constrains the slot to [0, ehash_mask], which is always within the allocated ehash array bounds. This is standard kernel hash-table lookup discipline — the raw port value is never used directly as an array index; it goes through a hash function and then a bitmask. There is no OOB access possible regardless of what value ntohs(th->dest) holds.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 36
Taint snippetsk = __inet6_lookup_established(net, &hdr->saddr, th->source,
Tainted varntohs(th->dest)
Call siteline 36 — passes ntohs(th->dest) to __inet6_lookup_established()
Call snippetsk = __inet6_lookup_established(net, &hdr->saddr, th->source,
Subscript (in callee)[] line 101
Sink snippethead = &hashinfo->ehash[slot];
Possibly guardedno
Dismissed: The tainted port value ntohs(th->dest) is passed as 'hnum' to __inet6_lookup_established(), where it is fed into inet6_ehashfn() to produce a 32-bit hash. The slot is then computed as 'hash & hashinfo->ehash_mask', which constrains the index to the valid range of the ehash array regardless of the input value. No counterexample exists: any value of ntohs(th->dest) (0–65535) yields a hash that, after masking with ehash_mask, stays within the allocated array. The static scanner flagged the array subscript use but failed to see the intermediate masking step that makes the access safe.

__udp6_lib_lookup() — net/ipv6/udp.c FP confidence=high

Both findings are false positives. Finding #1: the provided source for udp6_lib_lookup4() shows it unconditionally returns NULL with no array access. The scanner's reference to a sink at line 305 does not match the provided source. Finding #2: udp_hashfn() applies a bitmask (hnum & udptable->mask) to constrain the slot index to the valid range of udptable->hash[], making OOB impossible regardless of the input value of hnum. This is standard kernel hash table practice.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 351
Taint snippetunsigned short hnum = ntohs(dport);
Tainted varhnum
Call siteline 360 — passes hnum to udp6_lib_lookup4()
Call snippetresult = udp6_lib_lookup4(net, saddr, sport, daddr, hnum,
Subscript (in callee)[] line 305
Sink snippethslot4 = &udptable->hash4[slot];
Possibly guardedno
Dismissed: The provided source of udp6_lib_lookup4() shows it returns NULL unconditionally. The scanner references a sink at line 305 that does not exist in the provided callee body. False positive due to stale or incorrect line reference — the function has no array access.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 351
Taint snippetunsigned short hnum = ntohs(dport);
Tainted varhnum
Call siteline 399 — passes hnum to udp6_lib_lookup1()
Call snippetresult = udp6_lib_lookup1(net, saddr, sport, daddr, hnum, dif, sdif,
Subscript (in callee)[] line 203
Sink snippetstruct udp_hslot *hslot = &udptable->hash[slot];
Possibly guardedno
Dismissed: udp_hashfn(net, hnum, udptable->mask) computes 'hnum & mask' (standard kernel implementation), which constrains slot to [0, mask] — exactly the valid index range of udptable->hash[]. No counterexample exists: any 16-bit hnum value, after masking with udptable->mask, yields a valid index. False positive.

__udp6_lib_mcast_deliver() — net/ipv6/udp.c FP confidence=high

The hash2 array subscript is bounded by '& udptable->mask' before use. Since udptable->hash2 has exactly (mask+1) entries, the ANDed value is always a valid index. This is the standard power-of-two hash table indexing idiom used throughout Linux networking. No counterexample can be constructed that would pass the mask operation yet produce an out-of-bounds index.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 944
Taint snippetunsigned short hnum = ntohs(uh->dest);
Tainted varhash2
Subscript[] line 964
Sink snippethslot = &udptable->hash2[hash2].hslot;
Possibly guardedno
Dismissed: hash2 = ipv6_portaddr_hash(net, daddr, hnum) & udptable->mask (line 962) constrains hash2 to [0, mask]. The hash2 array has mask+1 entries (power-of-two allocation), so hash2 is always a valid subscript. No counterexample exists: any input value of hnum, after passing through ipv6_portaddr_hash and being ANDed with mask, yields a value strictly less than the array size. This is a false positive from the static analyzer not modeling the mask-as-modulo pattern.

l2tp_udp_encap_recv() — net/l2tp/l2tp_core.c FP confidence=high

The scanner transitively taints 'session' through the server-supplied session_id used as a lookup key in l2tp_v3_session_get(). However, the returned session struct is a kernel-internal object whose fields (peer_cookie_len, peer_cookie) are set during local session configuration, not populated from the incoming network packet. Additionally, l2tp_v3_ensure_opt_in_linear() validates that the skb contains at least peer_cookie_len bytes before l2tp_recv_common() is called, so the memcmp is safe.

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 1073
Taint snippetsession_id = ntohl(*(__be32 *)ptr);
Tainted varsession
Call siteline 1101 — passes session to l2tp_recv_common()
Call snippetl2tp_recv_common(session, skb, ptr, optr, hdrflags, length);
Sink (in callee)memcmp() line 874 (arg 2, role=size)
Sink snippetif (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) {
Possibly guardedyes (heuristic)
Dismissed: The taint propagation is a false positive. 'session_id' is server-supplied, but 'session' is a kernel-internal struct looked up by that ID from a kernel IDR. session->peer_cookie_len is a locally-configured field, not a network-supplied value. Furthermore, l2tp_v3_ensure_opt_in_linear() (called at line 1096, before l2tp_recv_common() at line 1101) calls pskb_may_pull() with off+opt_len where opt_len includes peer_cookie_len, ensuring the packet buffer covers the bytes that memcmp will read. No counterexample exists: an attacker cannot craft peer_cookie_len to an arbitrary value via the incoming packet.

l2tp_ip_recv() — net/l2tp/l2tp_ip.c FP confidence=high

The function correctly validates the skb buffer via pskb_may_pull (line 139) and l2tp_v3_ensure_opt_in_linear() before calling l2tp_recv_common(). The taint chain session_id → session → session->peer_cookie_len is a false positive: session_id is only used as a lookup key into a kernel IDR table; the returned session struct was created during L2TP session establishment (control plane), and its peer_cookie_len field is not directly populated from this received data packet. The scanner incorrectly propagates taint through the IDR lookup to all fields of the fetched kernel object.

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 145
Taint snippetsession_id = ntohl(*((__be32 *)ptr));
Tainted varsession
Call siteline 169 — passes session to l2tp_recv_common()
Call snippetl2tp_recv_common(session, skb, ptr, optr, 0, skb->len);
Sink (in callee)memcmp() line 874 (arg 2, role=size)
Sink snippetif (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) {
Possibly guardedyes (heuristic)
Dismissed: session_id from the packet is used only as an IDR lookup key. The returned session object is a kernel-internal struct whose peer_cookie_len was set during session creation via the L2TP control plane, not read from this data packet. l2tp_v3_ensure_opt_in_linear() validates that pskb_may_pull(skb, off + peer_cookie_len + l2specific_len) succeeds before l2tp_recv_common() is called, ensuring the skb-side buffer for memcmp() is valid. No counterexample can be constructed where an attacker-controlled value in this packet directly corrupts peer_cookie_len. This is a classic false positive from taint propagation through a pointer lookup.

l2tp_ip6_recv() — net/l2tp/l2tp_ip6.c FP confidence=high

The function correctly validates the received packet: pskb_may_pull() ensures the first 4 bytes are linear before reading session_id; l2tp_v3_session_get() performs a kernel IDR lookup using session_id as a key and returns a kernel-internal struct or NULL; NULL checks follow both the session lookup and tunnel dereference; l2tp_v3_ensure_opt_in_linear() validates that optional fields fit in the linear region before l2tp_recv_common() is called. The taint propagation from session_id to session->peer_cookie_len is a false positive because session is a kernel-internal object whose fields (peer_cookie_len, peer_cookie) are set by the kernel during session configuration, not derived from the incoming packet's content.

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 155
Taint snippetsession_id = ntohl(*((__be32 *)ptr));
Tainted varsession
Call siteline 179 — passes session to l2tp_recv_common()
Call snippetl2tp_recv_common(session, skb, ptr, optr, 0, skb->len);
Sink (in callee)memcmp() line 874 (arg 2, role=size)
Sink snippetif (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) {
Possibly guardedyes (heuristic)
Dismissed: The scanner incorrectly propagates taint from session_id (network-supplied) through l2tp_v3_session_get() to the returned session object. However, session is a kernel-internal struct looked up by session_id as a key in a kernel IDR table. The fields session->peer_cookie_len and session->peer_cookie are populated by the kernel during L2TP session setup (not from the packet being processed). peer_cookie_len is bounded by L2TP_COOKIE_SIZE (8 bytes) and is kernel-controlled. No counterexample can be constructed: a remote peer cannot influence peer_cookie_len by choosing a particular session_id value — the worst case is the session is not found (returning NULL, which is checked). This is a textbook false positive of the 'lookup key taint propagation' pattern.

llc_sap_action_send_test_r() — net/llc/llc_s_ac.c FP confidence=high

data_size is genuinely network-supplied (from h_proto), and the subtraction can underflow if h_proto < 3, creating a large u32. However, the flagged sinks at llc_alloc_frame lines 56-57 (skb->protocol and skb->dev assignments) are not tainted pointer dereferences — they operate on the freshly-allocated skb pointer, not on any offset derived from data_size. The NULL check on nskb (line 165) protects against the case where alloc_skb fails due to the large size. The scanner has misidentified normal post-allocation field assignments as tainted pointer dereferences.

Finding #1 — Category E — cross-function via llc_alloc_frame() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 163
Taint snippetdata_size = ntohs(eth_hdr(skb)->h_proto) - 3;
Tainted vardata_size
Call siteline 164 — passes data_size to llc_alloc_frame()
Call snippetnskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U, data_size);
Pointer derefdata_size-> line 56
Sink snippetskb->protocol = htons(ETH_P_802_2);
Possibly guardedno
Dismissed: The sink at line 56 (skb->protocol = htons(ETH_P_802_2)) is a plain assignment to a field of the newly allocated skb. It does not use data_size as a pointer or index — data_size only affects the alloc_skb() size argument. If alloc_skb fails (which it will for absurdly large sizes), the NULL check at line 165 guards against use of nskb. No concrete counterexample exists where data_size causes a dereference at this sink. False positive.

Finding #2 — Category E — cross-function via llc_alloc_frame() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 163
Taint snippetdata_size = ntohs(eth_hdr(skb)->h_proto) - 3;
Tainted vardata_size
Call siteline 164 — passes data_size to llc_alloc_frame()
Call snippetnskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U, data_size);
Pointer derefdata_size-> line 57
Sink snippetskb->dev = dev;
Possibly guardedno
Dismissed: Same analysis as finding #1. The sink at line 57 (skb->dev = dev) is a plain assignment to the freshly allocated skb's dev field. data_size is not used as a pointer or array index at this sink — it only determined the allocation size. The NULL check on nskb protects against failed allocations. False positive.

llc_station_ac_send_test_r() — net/llc/llc_station.c FP confidence=high

The scanner's taint propagation is incorrect: it marks the skb pointer returned by alloc_skb() as tainted because the allocation size argument (data_size) was network-supplied, then flags subsequent field accesses on that pointer as 'tainted pointer dereferences.' In reality, alloc_skb() returns a kernel-allocated address — not a pointer derived from the network value — so skb->protocol and skb->dev accesses are normal and safe. The actual concern in this function is a potential integer underflow (h_proto < 3 → data_size wraps to large u32) followed by alloc_skb getting an excessive or overflowed size; alloc_skb would return NULL in that case, which is already handled. The flagged sinks themselves are not vulnerable.

Finding #1 — Category E — cross-function via llc_alloc_frame() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 77
Taint snippetdata_size = ntohs(eth_hdr(skb)->h_proto) - 3;
Tainted vardata_size
Call siteline 78 — passes data_size to llc_alloc_frame()
Call snippetnskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U, data_size);
Pointer derefdata_size-> line 56
Sink snippetskb->protocol = htons(ETH_P_802_2);
Possibly guardedno
Dismissed: The taint is genuinely network-supplied (Ethernet h_proto field). However, the flagged sink (skb->protocol at line 56) is a field write on a pointer returned by alloc_skb() — a kernel allocator. The scanner incorrectly propagates taint from the size argument through alloc_skb to the returned pointer. The returned skb address is not derived from the network-supplied value; it is a fresh kernel heap allocation. This is a false positive on the specific sink. A real (separate) concern is underflow if h_proto < 3, but alloc_skb failure is already handled by the NULL check.

Finding #2 — Category E — cross-function via llc_alloc_frame() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 77
Taint snippetdata_size = ntohs(eth_hdr(skb)->h_proto) - 3;
Tainted vardata_size
Call siteline 78 — passes data_size to llc_alloc_frame()
Call snippetnskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U, data_size);
Pointer derefdata_size-> line 57
Sink snippetskb->dev = dev;
Possibly guardedno
Dismissed: Same analysis as finding #1. The sink (skb->dev at line 57) is a field write on a kernel-allocated skb pointer, not a pointer derived from the network-supplied data_size. The scanner's taint propagation through alloc_skb's return value is incorrect. False positive on the specific sink classification.

ieee80211_process_addba_request() — net/mac80211/agg-rx.c FP confidence=high

tid is extracted from a 4-bit field (max value 15) which is always a valid index for IEEE80211_NUM_TIDS=16 sized arrays. buf_size is validated and clamped in __ieee80211_start_rx_ba_session() before the loop (lines 347-364 check buf_size > max_buf_size and clamp to sta->sta.max_rx_aggregation_subframes). All flagged accesses are protected by either inherent bit-width constraints or explicit callee-side validation.

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

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 487
Taint snippetcapab = le16_to_cpu(mgmt->u.action.addba_req.capab);
Tainted vartid
Call siteline 500 — passes tid to __ieee80211_start_rx_ba_session()
Call snippet__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
Subscript (in callee)[] line 371
Sink snippetif (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
Possibly guardedyes (heuristic)
Dismissed: tid is masked by IEEE80211_ADDBA_PARAM_TID_MASK and shifted to give a 4-bit value (0-15). tid_rx_token[] has IEEE80211_NUM_TIDS=16 entries. No counterexample exists: all 4-bit values are valid indices.

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

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 487
Taint snippetcapab = le16_to_cpu(mgmt->u.action.addba_req.capab);
Tainted vartid
Call siteline 500 — passes tid to __ieee80211_start_rx_ba_session()
Call snippet__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
Subscript (in callee)[] line 383
Sink snippettid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #1: tid is a 4-bit value (0-15), valid for all 16-element arrays. No counterexample possible.

Finding #3 — Category C — cross-function via __ieee80211_start_rx_ba_session() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 487
Taint snippetcapab = le16_to_cpu(mgmt->u.action.addba_req.capab);
Tainted vartid
Call siteline 500 — passes tid to __ieee80211_start_rx_ba_session()
Call snippet__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
Subscript (in callee)[] line 452
Sink snippetrcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #1: tid is a 4-bit value (0-15), valid for all 16-element arrays. No counterexample possible.

Finding #4 — Category C — cross-function via __ieee80211_start_rx_ba_session() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 487
Taint snippetcapab = le16_to_cpu(mgmt->u.action.addba_req.capab);
Tainted vartid
Call siteline 500 — passes tid to __ieee80211_start_rx_ba_session()
Call snippet__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
Subscript (in callee)[] line 463
Sink snippetsta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
Possibly guardedyes (heuristic)
Dismissed: Same as finding #1: tid is a 4-bit value (0-15), valid for all 16-element arrays. No counterexample possible.

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

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 487
Taint snippetcapab = le16_to_cpu(mgmt->u.action.addba_req.capab);
Tainted varbuf_size
Call siteline 500 — passes buf_size to __ieee80211_start_rx_ba_session()
Call snippet__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
Loopfor_loop line 427
Sink snippetfor (i = 0; i < buf_size; i++)
Possibly guardedyes (heuristic)
Dismissed: buf_size is validated in __ieee80211_start_rx_ba_session() at lines 347-364: rejected if > max_buf_size, then clamped to sta->sta.max_rx_aggregation_subframes. The loop at line 427 iterates over an array allocated with buf_size elements (line 424: kzalloc(sizeof(*tid_agg_rx->reorder_buf) * buf_size)), so the loop bound equals the allocation size after clamping. No counterexample possible.

ieee80211_process_addba_resp() — net/mac80211/agg-tx.c FP confidence=high

The tid value is extracted from a 4-bit bitfield (IEEE80211_ADDBA_PARAM_TID_MASK) via u16_get_bits(), constraining it to the range [0,15]. All arrays indexed by tid (txq[], addba_req_num[], tid_start_tx[]) are sized IEEE80211_NUM_TIDS=16, so indices 0-15 are all in bounds. No counterexample exists where a valid 4-bit tid could produce an OOB access. The scanner correctly identifies that no explicit bounds check is present but fails to account for the bit-mask constraint that implicitly bounds the value.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 989
Taint snippetcapab = le16_to_cpu(mgmt->u.action.addba_resp.capab);
Tainted vartid
Subscript[] line 1002
Sink snippettxq = sta->sta.txq[tid];
Possibly guardedno
Dismissed: tid is extracted via u16_get_bits(capab, IEEE80211_ADDBA_PARAM_TID_MASK) where the mask selects a 4-bit field, limiting tid to [0,15]. sta->sta.txq[] is sized IEEE80211_NUM_TIDS+1 or similar (at least 16 entries). No counterexample exists: a 4-bit field cannot produce a value >= 16.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 989
Taint snippetcapab = le16_to_cpu(mgmt->u.action.addba_resp.capab);
Tainted vartid
Subscript[] line 1054
Sink snippetsta->ampdu_mlme.addba_req_num[tid] = 0;
Possibly guardedno
Dismissed: Same tid value (4-bit masked) indexes addba_req_num[IEEE80211_NUM_TIDS] which has 16 elements. Values 0-15 are all valid. No counterexample possible.

Finding #3 — Category C — cross-function via __ieee80211_stop_tx_ba_session() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 989
Taint snippetcapab = le16_to_cpu(mgmt->u.action.addba_resp.capab);
Tainted vartid
Call siteline 1066 — passes tid to __ieee80211_stop_tx_ba_session()
Call snippet__ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_DECLINED);
Subscript (in callee)[] line 325
Sink snippettid_tx = sta->ampdu_mlme.tid_start_tx[tid];
Possibly guardedno
Dismissed: tid passed to __ieee80211_stop_tx_ba_session() is still the 4-bit masked value [0,15]. tid_start_tx[tid] at line 325 indexes a 16-element array. No OOB possible.

Finding #4 — Category C — cross-function via __ieee80211_stop_tx_ba_session() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 989
Taint snippetcapab = le16_to_cpu(mgmt->u.action.addba_resp.capab);
Tainted vartid
Call siteline 1066 — passes tid to __ieee80211_stop_tx_ba_session()
Call snippet__ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_DECLINED);
Subscript (in callee)[] line 327
Sink snippetsta->ampdu_mlme.tid_start_tx[tid] = NULL;
Possibly guardedno
Dismissed: Same as finding #3 — line 327 sets tid_start_tx[tid]=NULL, also within the 16-element array bounds guaranteed by the 4-bit mask on tid.
The function has good validation discipline: ieee80211_mle_reconf_sta_prof_size_ok() validates the per-STA profile structure before any field accesses; link_id is masked with IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID (a 4-bit field yielding values 0-15) before assignment to u8, causing no actual truncation loss; and the explicit bounds check `link_id >= IEEE80211_MLD_MAX_NUM_LINKS` at line 241 guards both array subscript accesses at lines 244 and 255. No counterexample can be constructed that passes the bounds check yet causes OOB.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 239
Taint snippetlink_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID;
Tainted varlink_id
Truncationline 239: 16 → 8-bit u8
Sink snippetlink_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID;
Possibly guardedno
Dismissed: IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID is a bitmask for the link ID field in the per-STA profile control word. Link IDs in 802.11 MLE are 4-bit values (0-15), so the mask limits the result to at most 15, which fits in a u8 without any truncation loss. The subsequent bounds check `link_id >= IEEE80211_MLD_MAX_NUM_LINKS` (which is 15) further confirms the value is well-controlled. No counterexample exists where masking followed by bounds-check fails.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 238
Taint snippetcontrol = le16_to_cpu(prof->control);
Tainted varlink_id
Subscript[] line 244
Sink snippetlink = sdata_dereference(sdata->link[link_id], sdata);
Possibly guardedyes (heuristic)
Dismissed: The explicit check `if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) return;` at line 241-242 occurs before the array access at line 244. sdata->link[] is sized IEEE80211_MLD_MAX_NUM_LINKS, so any link_id passing the check is a valid array index. No counterexample can be constructed: any value >= IEEE80211_MLD_MAX_NUM_LINKS causes early return; any value < IEEE80211_MLD_MAX_NUM_LINKS is in-bounds.

Finding #3 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 238
Taint snippetcontrol = le16_to_cpu(prof->control);
Tainted varlink_id
Subscript[] line 255
Sink snippetlink_sta = sdata_dereference(sta->link[link_id], sdata);
Possibly guardedyes (heuristic)
Dismissed: Same link_id value and same bounds check as finding #2. The check at line 241-242 guards this access at line 255 as well. sta->link[] is also sized IEEE80211_MLD_MAX_NUM_LINKS. No counterexample exists. False positive.

ieee80211_eht_cap_ie_to_sta_eht_cap() — net/mac80211/eht.c FP confidence=medium

The function has reasonable bounds checking discipline. The truncation of eht_ppe_size from a value derived from a u16 input is a theoretical concern, but the truncation makes the memcpy copy FEWER bytes than intended (never more), so it cannot cause an OOB write to the destination. The destination guard at line 54 checks the already-truncated u8 value. An adversarial crafted value that truncates would cause incorrect (smaller) copying but not memory corruption. The source buffer is validated via eht_cap_len at line 58 after computing eht_total_size which includes eht_ppe_size.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourceget_unaligned_le16() line 48
Taint snippeteht_ppe_size =
Tainted vareht_ppe_size
Truncationline 48: 16 → 8-bit u8
Sink snippeteht_ppe_size =
Possibly guardedno
Dismissed: The truncation from u16 to u8 happens BEFORE the bounds check at line 54. However, truncation can only make the value smaller (e.g., 256→0, 257→1), meaning the memcpy would copy fewer bytes than the actual PPE size — a correctness bug but not an OOB write. No counterexample exists where the truncated value causes eht_ppe_size to exceed sizeof(eht_ppe_thres) when the true value would not, because truncation always reduces the value. The risk is the opposite: a too-small copy silently succeeds.

Finding #2 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourceget_unaligned_le16() line 47
Taint snippeteht_ppe_hdr = get_unaligned_le16(eht_cap_ie_elem->optional + mcs_nss_size);
Tainted vareht_ppe_size
Sinkmemcpy() line 71 (arg 2, role=size)
Sink snippetmemcpy(eht_cap->eht_ppe_thres,
Possibly guardedyes (heuristic)
Dismissed: Destination check: line 54 guards eht_ppe_size <= sizeof(eht_ppe_thres). Source check: line 58 guards eht_cap_len >= eht_total_size which includes eht_ppe_size. Both checks use the (possibly truncated) u8 value. Since truncation only makes the value smaller, the destination check cannot be bypassed to allow OOB write. Cannot construct a counterexample where truncated eht_ppe_size exceeds sizeof(eht_ppe_thres) while original would not — truncation reduces the value.

ieee80211_process_delba() — net/mac80211/ht.c FP confidence=high

tid is derived from a 4-bit bitfield (bits 15:12 of params, masked with IEEE80211_DELBA_PARAM_TID_MASK then shifted right 12), constraining it to [0, 15]. The arrays tid_rx[], tid_start_tx[], and agg_session_valid are all IEEE80211_NUM_TIDS (16) elements wide, so indices 0-15 are all valid. The static analyzer propagates taint through the le16_to_cpu() call but does not track the value-range constraint imposed by the subsequent mask-and-shift operation. No counterexample can be constructed because the mask operation makes tid > 15 impossible.

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

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 466
Taint snippetparams = le16_to_cpu(mgmt->u.action.delba.params);
Tainted vartid
Call siteline 476 — passes tid to __ieee80211_stop_rx_ba_session()
Call snippet__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
Subscript (in callee)[] line 72
Sink snippettid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
Possibly guardedno
Dismissed: tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12 constrains tid to [0,15]. sta->ampdu_mlme.tid_rx[] has IEEE80211_NUM_TIDS=16 entries. No OOB possible; cannot construct a counterexample.

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

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 466
Taint snippetparams = le16_to_cpu(mgmt->u.action.delba.params);
Tainted vartid
Call siteline 476 — passes tid to __ieee80211_stop_rx_ba_session()
Call snippet__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
Subscript (in callee)[] line 78
Sink snippetRCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
Possibly guardedno
Dismissed: Same as finding 1: tid is 4-bit masked, array is 16 elements. RCU_INIT_POINTER access at tid_rx[tid] is safe for all possible tid values.

Finding #3 — Category C — cross-function via __ieee80211_stop_tx_ba_session() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 466
Taint snippetparams = le16_to_cpu(mgmt->u.action.delba.params);
Tainted vartid
Call siteline 479 — passes tid to __ieee80211_stop_tx_ba_session()
Call snippet__ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_PEER_REQUEST);
Subscript (in callee)[] line 325
Sink snippettid_tx = sta->ampdu_mlme.tid_start_tx[tid];
Possibly guardedno
Dismissed: tid is constrained to [0,15] by the mask IEEE80211_DELBA_PARAM_TID_MASK >> 12. tid_start_tx[] is IEEE80211_NUM_TIDS=16 elements. No counterexample possible.

Finding #4 — Category C — cross-function via __ieee80211_stop_tx_ba_session() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 466
Taint snippetparams = le16_to_cpu(mgmt->u.action.delba.params);
Tainted vartid
Call siteline 479 — passes tid to __ieee80211_stop_tx_ba_session()
Call snippet__ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_PEER_REQUEST);
Subscript (in callee)[] line 327
Sink snippetsta->ampdu_mlme.tid_start_tx[tid] = NULL;
Possibly guardedno
Dismissed: Same as finding 3: write to tid_start_tx[tid] where tid in [0,15] and array has 16 entries. False positive due to analyzer not tracking bitmask value constraints.

ieee80211_mesh_rx_bcn_presp() — net/mac80211/mesh.c FP confidence=high

The scanner incorrectly propagates taint from `type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE` through the call to `ieee802_11_parse_elems(..., type, ...)` to the returned `elems` pointer. However, `elems` is a kernel-allocated struct (`struct ieee802_11_elems`) populated by the element parser, which validates all element lengths and offsets during parsing. The `type` parameter only affects parsing mode/behavior, not the memory safety of the returned struct. Similarly, `channel` is obtained from `ieee80211_get_channel()`, a kernel-internal lookup unrelated to packet offsets. All flagged dereferences are on kernel-internal structures, not raw packet pointers. The `baselen > len` check at line 1464 ensures the element region is valid before parsing.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1449
Taint snippetu16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
Tainted varelems
Pointer derefelems->mesh_id line 1473
Sink snippetif ((!elems->mesh_id || !elems->mesh_config) ||
Possibly guardedno
Dismissed: elems is a kernel-allocated struct returned by ieee802_11_parse_elems(). The scanner incorrectly propagates taint from `type` (passed as a parameter) to the return value `elems`. The `elems->mesh_id` field is a pointer set by the element parser with internal bounds validation. This is a false positive due to incorrect taint propagation through a function call return value.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1449
Taint snippetu16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
Tainted varelems
Pointer derefelems->rsn line 1474
Sink snippet(elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
Possibly guardedno
Dismissed: Same false positive pattern as finding #1. elems->rsn is a pointer field set by the kernel element parser, not a raw packet offset. Taint from `type` should not propagate to the return struct of ieee802_11_parse_elems().

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1449
Taint snippetu16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
Tainted varelems
Pointer derefelems->rsn line 1475
Sink snippet(!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
Possibly guardedno
Dismissed: Same false positive as finding #2. elems->rsn on line 1475 is the same field, same struct, same analysis applies.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1449
Taint snippetu16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
Tainted varelems
Pointer derefelems->ds_params line 1478
Sink snippetif (elems->ds_params)
Possibly guardedno
Dismissed: elems->ds_params is a pointer field in the kernel-allocated elems struct. The null check `if (elems->ds_params)` at line 1478 guards the access at line 1479. The element parser validates the DS params element length before setting this pointer. False positive.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1449
Taint snippetu16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
Tainted varelems
Pointer derefelems->ds_params line 1479
Sink snippetfreq = ieee80211_channel_to_frequency(elems->ds_params[0], band);
Possibly guardedno
Dismissed: elems->ds_params[0] is accessed after the null check at line 1478. The DS Parameters element is exactly 1 byte in 802.11 (the channel number), and the element parser validates this before setting the pointer. False positive.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1449
Taint snippetu16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
Tainted varchannel
Pointer derefchannel->flags line 1485
Sink snippetif (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
Possibly guardedno
Dismissed: channel is the return value of ieee80211_get_channel(), a kernel-internal function that looks up a channel in the wiphy's channel table. It has no relationship to packet offsets. The null check `!channel` at line 1485 guards the `channel->flags` access. This is a completely spurious taint path; the scanner has incorrectly traced taint from `type` through `freq` computation to `channel`. False positive.

Finding #7 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele16_to_cpu() line 1449
Taint snippetu16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
Tainted varelems
Pointer derefelems->mesh_config line 1506
Sink snippetelems->mesh_config, rx_status);
Possibly guardedno
Dismissed: elems->mesh_config is accessed at line 1506. It was already verified non-null at line 1473 (`!elems->mesh_config` check). The field is set by the kernel element parser with internal bounds validation. False positive.

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

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 1449
Taint snippetu16 type = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_TYPE;
Tainted varelems
Call siteline 1488 — passes elems to mesh_matches_local()
Call snippetif (mesh_matches_local(sdata, elems)) {
Sink (in callee)memcmp() line 85 (arg 2, role=size)
Sink snippetmemcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
Possibly guardedyes (heuristic)
Dismissed: ie->mesh_id_len is set by the element parser (ieee802_11_parse_elems_full) which validates that the mesh_id element fits within the received buffer before recording its length. Therefore mesh_id_len is bounded by the element's actual in-packet length. The memcmp() in mesh_matches_local() uses this validated length to compare against ifmsh->mesh_id (which has its own length ifmsh->mesh_id_len — the equality check `ifmsh->mesh_id_len == ie->mesh_id_len` at line 84 ensures both lengths match before memcmp). No counterexample exists because the parser-validated length cannot exceed the element's true packet bounds. False positive.

mesh_rmc_check() — net/mac80211/mesh.c FP confidence=high

The index 'idx' is computed as le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask, where rmc->idx_mask is RMC_BUCKETS-1 (255 = 0xFF). This masking operation ensures the result always fits in a u8 and is always a valid index into the rmc->bucket[] array (sized RMC_BUCKETS=256). No counterexample exists that would pass the mask and cause OOB access. All three findings are false positives stemming from the scanner not recognizing that the idx_mask is a power-of-two-minus-one kernel-controlled bitmask that bounds the index.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele32_to_cpu() line 241
Taint snippetidx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
Tainted varidx
Truncationline 241: 32 → 8-bit u8
Sink snippetidx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
Possibly guardedno
Dismissed: The scanner flags the 32-to-8 bit truncation, but explicitly says to mark as false positive when masking is used. The expression '& rmc->idx_mask' where idx_mask = RMC_BUCKETS-1 = 0xFF constrains the result to [0,255] before truncation to u8, so no information is lost. No counterexample can be constructed.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele32_to_cpu() line 241
Taint snippetidx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
Tainted varidx
Subscript[] line 242
Sink snippethlist_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
Possibly guardedno
Dismissed: idx is bounded to [0, RMC_BUCKETS-1] by the '& rmc->idx_mask' operation (idx_mask = RMC_BUCKETS-1). The bucket array has RMC_BUCKETS entries. No OOB is possible. Cannot construct a counterexample: any seqnum masked with 0xFF gives a value in [0,255] which is valid for a 256-entry array.

Finding #3 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele32_to_cpu() line 241
Taint snippetidx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
Tainted varidx
Subscript[] line 260
Sink snippethlist_add_head(&p->list, &rmc->bucket[idx]);
Possibly guardedno
Dismissed: Same analysis as finding #2 applies to the second use of idx at line 260. The mask applied at computation time fully constrains the index. False positive.
The function has solid validation discipline: ie_len is validated against exact expected values for each frame type before the peering IEs are parsed; server-supplied values (plid, llid) are u16 reads used only in limited ways. The static analyzer over-propagates taint through mesh_plink_get_event(), treating its enum return value as tainted because llid was an input. In reality, mesh_plink_get_event() returns compile-time enum constants, not arbitrary derivations of the network-supplied llid. Additionally, the PLINK_UNDEFINED guard at line 1199 prevents mesh_plink_fsm() from being called with invalid event values.

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

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 1168
Taint snippetllid = get_unaligned_le16(PLINK_GET_PLID(elems->peering));
Tainted varevent
Call siteline 1212 — passes event to mesh_plink_fsm()
Call snippetchanged |= mesh_plink_fsm(sdata, sta, event);
Subscript (in callee)[] line 878
Sink snippetmplstates[sta->mesh->plink_state], mplevents[event]);
Possibly guardedyes (heuristic)
Dismissed: The taint propagation from llid (network-supplied u16) to 'event' is incorrect — mesh_plink_get_event() returns a fixed enum plink_event value (OPN_ACPT, CNF_ACPT, CLS_ACPT, OPN_RJCT, CNF_RJCT, PLINK_UNDEFINED), not an arbitrary value derived from llid. The guard at line 1199 ensures PLINK_UNDEFINED causes an early return before mesh_plink_fsm() is called. No counterexample can be constructed: any valid enum value from mesh_plink_get_event() that passes the guards is a defined constant that indexes safely into mplevents[]. This is an over-taint false positive.
The taint source (le16_to_cpu() at line 5862) reads mgmt->frame_control into parse_params.type. The scanner incorrectly propagates taint from parse_params through ieee802_11_parse_elems_full() to elems. In reality: (1) elems is validated output from the parser, not raw server data; (2) the parser validates all element pointers within the input buffer; (3) ieee80211_eht_cap_ie_to_sta_eht_cap() internally validates eht_cap_len against all computed sizes (mcs_nss_size, eht_ppe_size) before any memcpy or array subscript; (4) the memcmp sink in ieee80211_config_bw() uses sizeof(elems->tpe) which is compile-time constant. All findings are false positives.

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

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 5862
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 6045 — passes elems to ieee80211_config_bw()
Call snippetif (ieee80211_config_bw(link, elems,
Sink (in callee)memcmp() line 1690 (arg 2, role=size)
Sink snippetif (memcmp(&link->conf->tpe, &elems->tpe, sizeof(elems->tpe))) {
Possibly guardedno
Dismissed: The memcmp at line 1690 uses sizeof(elems->tpe) as the size argument - this is a compile-time constant sizeof, not a server-supplied value. The scanner misidentified this as a size sink because it followed taint through elems, but sizeof() of a struct field is always a compile-time constant regardless of taint. No counterexample exists.

Finding #2 — Category H — cross-function via ieee80211_eht_cap_ie_to_sta_eht_cap() — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 5862
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 6127 — passes elems to ieee80211_eht_cap_ie_to_sta_eht_cap()
Call snippetieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
Truncationline 48: None → None-bit
Sink snippeteht_ppe_size =
Possibly guardedno
Dismissed: eht_ppe_size is computed from get_unaligned_le16() of eht_cap_ie_elem->optional data, but is bounded by: (1) check at line 44 that eht_cap_len >= eht_total_size + sizeof(u16) before reading the PPE header; (2) check at line 54 that eht_ppe_size <= sizeof(eht_cap->eht_ppe_thres); (3) check at line 58 that eht_cap_len >= eht_total_size. The narrowing assignment to u8 eht_ppe_size is safe because line 54 ensures it fits. Cannot construct counterexample that passes all guards.

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

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 5862
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 6127 — passes elems to ieee80211_eht_cap_ie_to_sta_eht_cap()
Call snippetieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
Sink (in callee)memcpy() line 68 (arg 2, role=size)
Sink snippetmemcpy(&eht_cap->eht_mcs_nss_supp, pos, mcs_nss_size);
Possibly guardedno
Dismissed: mcs_nss_size is derived from ieee80211_eht_mcs_nss_size() which computes a size based on capability bits. The check at line 58 (eht_cap_len < eht_total_size where eht_total_size = sizeof(eht_cap_elem) + mcs_nss_size) ensures mcs_nss_size <= eht_cap_len - sizeof(eht_cap_elem). The destination eht_mcs_nss_supp is zeroed and sized as the union, and memcpy copies at most mcs_nss_size bytes which is bounded. No counterexample exists.

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

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 5862
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 6127 — passes elems to ieee80211_eht_cap_ie_to_sta_eht_cap()
Call snippetieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
Sink (in callee)memcpy() line 71 (arg 2, role=size)
Sink snippetmemcpy(eht_cap->eht_ppe_thres,
Possibly guardedyes (heuristic)
Dismissed: eht_ppe_size at line 71 memcpy is guarded by line 54 check (eht_ppe_size <= sizeof(eht_cap->eht_ppe_thres)) and the eht_cap_len >= eht_total_size check at line 58. The destination eht_ppe_thres has size sizeof(eht_cap->eht_ppe_thres) and eht_ppe_size is verified <= that size. No counterexample exists.

Finding #5 — Category C — cross-function via ieee80211_eht_cap_ie_to_sta_eht_cap() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 5862
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 6127 — passes elems to ieee80211_eht_cap_ie_to_sta_eht_cap()
Call snippetieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
Subscript (in callee)[] line 72
Sink snippet&eht_cap_ie_elem->optional[mcs_nss_size],
Possibly guardedno
Dismissed: The array subscript eht_cap_ie_elem->optional[mcs_nss_size] at line 72 is reached only when eht_ppe_size > 0 (line 70). The check at line 58 ensures eht_cap_len >= sizeof(eht_cap_elem) + mcs_nss_size + eht_ppe_size, which means the optional[] array (which immediately follows the fixed struct) has at least mcs_nss_size + eht_ppe_size bytes available. The subscript access is within bounds. No counterexample exists.

ieee80211_max_rx_chains() — net/mac80211/mlme.c FP confidence=high

Both findings are false positives. The scanner correctly identified le16_to_cpu() as a taint source but missed that the bitwise mask '& 3' applied before assignment to u8 limits the value to [0,3], making truncation impossible. The values are used only for comparison against IEEE80211_VHT_MCS_NOT_SUPPORTED (==3) and for updating a chains counter bounded by the loop index i in [0,7]. The function also properly validates datalen before accessing he_mcs_nss_supp fields.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 6429
Taint snippetu8 mcs_80 = mcs_80_map >> (2 * i) & 3;
Tainted varmcs_80
Truncationline 6429: 16 → 8-bit u8
Sink snippetu8 mcs_80 = mcs_80_map >> (2 * i) & 3;
Possibly guardedno
Dismissed: The expression '(mcs_80_map >> (2 * i)) & 3' applies a bitmask of 3 (0b11) before assignment to u8, limiting the value to [0,3]. No truncation loss is possible regardless of the 16-bit input. Counterexample test: even with mcs_80_map=0xFFFF and i=0, the result is 0xFFFF & 3 = 3, which fits in u8. No counterexample can be constructed.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 6445
Taint snippetu8 mcs_160 = mcs_160_map >> (2 * i) & 3;
Tainted varmcs_160
Truncationline 6445: 16 → 8-bit u8
Sink snippetu8 mcs_160 = mcs_160_map >> (2 * i) & 3;
Possibly guardedno
Dismissed: Identical pattern to finding #1: '(mcs_160_map >> (2 * i)) & 3' masks to 2 bits before u8 assignment. The & 3 mask guarantees the value is in [0,3], which trivially fits in u8 with no information loss. No counterexample can be constructed.

ieee80211_ml_epcs() — net/mac80211/mlme.c FP confidence=high

The function has proper validation: (1) link_id is masked to 4 bits before truncation to u8, making the truncation safe; (2) link_id is bounds-checked against IEEE80211_MLD_MAX_NUM_LINKS before array indexing; (3) cfg80211_defragment_element validates the element fits within the buffer; (4) ieee802_11_parse_elems validates all elements in the defragmented payload and returns a locally-allocated struct — link_elems fields are set by the kernel parser, not directly derived from untrusted offsets.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourceget_unaligned_le16() line 11666
Taint snippetlink_id = control & IEEE80211_MLE_STA_EPCS_CONTROL_LINK_ID;
Tainted varlink_id
Truncationline 11666: 16 → 8-bit u8
Sink snippetlink_id = control & IEEE80211_MLE_STA_EPCS_CONTROL_LINK_ID;
Possibly guardedno
Dismissed: IEEE80211_MLE_STA_EPCS_CONTROL_LINK_ID masks to 4 bits (0x000F), so the masked value is at most 15, which trivially fits in u8. No counterexample exists: any u16 AND 0xF <= 15 < 256. Truncation is safe.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 11665
Taint snippetcontrol = get_unaligned_le16(pos);
Tainted varlink_id
Subscript[] line 11671
Sink snippetlink = sdata_dereference(sdata->link[link_id], sdata);
Possibly guardedyes (heuristic)
Dismissed: link_id is bounded to [0, IEEE80211_MLD_MAX_NUM_LINKS-1] by the check at line 11668 before the array subscript at line 11671. The mask ensures link_id <= 15, and the bounds check ensures link_id < IEEE80211_MLD_MAX_NUM_LINKS. No counterexample: any value passing the guard is a valid index.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourceget_unaligned_le16() line 11665
Taint snippetcontrol = get_unaligned_le16(pos);
Tainted varlink_elems
Pointer dereflink_elems->wmm_param line 11693
Sink snippetlink_elems->wmm_param,
Possibly guardedno
Dismissed: link_elems is a kernel-allocated struct returned by ieee802_11_parse_elems(), which internally validates all element bounds. The wmm_param field is a pointer set by the parser to a validated location within the parsed buffer, not a raw server-supplied offset. The taint chain through the parser is a false positive.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourceget_unaligned_le16() line 11665
Taint snippetcontrol = get_unaligned_le16(pos);
Tainted varlink_elems
Pointer dereflink_elems->wmm_param_len line 11694
Sink snippetlink_elems->wmm_param_len,
Possibly guardedno
Dismissed: Same reasoning as finding #3: link_elems->wmm_param_len is populated by the element parser with validated length, not a raw server value used without bounds checking.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourceget_unaligned_le16() line 11665
Taint snippetcontrol = get_unaligned_le16(pos);
Tainted varlink_elems
Pointer dereflink_elems->mu_edca_param_set line 11695
Sink snippetlink_elems->mu_edca_param_set))
Possibly guardedno
Dismissed: Same reasoning as findings #3 and #4: link_elems->mu_edca_param_set is set by the kernel element parser from validated buffer contents. The scanner's taint propagation through ieee802_11_parse_elems is a false positive.

ieee80211_ml_reconfiguration() — net/mac80211/mlme.c FP confidence=high

The code has proper bounds validation. link_id is masked with IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID (a small bitmask, 4 bits for link IDs 0-15) and then checked against IEEE80211_MLD_MAX_NUM_LINKS at line 7666 before any array access in the first loop. In the second loop, for_each_set_bit() with IEEE80211_MLD_MAX_NUM_LINKS as the upper bound guarantees link_id is within range, and removed_links can only contain bits that passed the first loop's bounds check. All findings are false positives.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 7664
Taint snippetlink_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID;
Tainted varlink_id
Truncationline 7664: 16 → 8-bit u8
Sink snippetlink_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID;
Possibly guardedno
Dismissed: IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID is a bitmask for a 4-bit link ID field (values 0-15), which fits within u8. The masking operation (& mask) before assignment to u8 prevents any meaningful truncation. Additionally, the subsequent check at line 7666 against IEEE80211_MLD_MAX_NUM_LINKS (which is 15) makes this safe. Cannot construct counterexample where truncation causes a different value than without truncation given the mask is ≤ 0x0F.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 7663
Taint snippetcontrol = le16_to_cpu(prof->control);
Tainted varlink_id
Subscript[] line 7682
Sink snippetlink_removal_timeout[link_id] = get_unaligned_le16(pos);
Possibly guardedyes (heuristic)
Dismissed: Line 7666 explicitly checks `if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) continue;` before reaching line 7682. link_removal_timeout is declared with size IEEE80211_MLD_MAX_NUM_LINKS. Cannot construct a counterexample — the guard ensures link_id < IEEE80211_MLD_MAX_NUM_LINKS before the array write.

Finding #3 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 7663
Taint snippetcontrol = le16_to_cpu(prof->control);
Tainted varlink_id
Subscript[] line 7699
Sink snippetsdata_dereference(sdata->vif.link_conf[link_id], sdata);
Possibly guardedyes (heuristic)
Dismissed: In the second loop, link_id comes from for_each_set_bit(&removed_links, IEEE80211_MLD_MAX_NUM_LINKS), which only iterates bits 0..IEEE80211_MLD_MAX_NUM_LINKS-1. removed_links is only populated with BIT(link_id) values that already passed the bounds check at line 7666. sdata->vif.link_conf has IEEE80211_MLD_MAX_NUM_LINKS entries. No counterexample possible.

Finding #4 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 7663
Taint snippetcontrol = le16_to_cpu(prof->control);
Tainted varlink_id
Subscript[] line 7707
Sink snippetif (link_removal_timeout[link_id] < 1)
Possibly guardedyes (heuristic)
Dismissed: Same reasoning as finding #3. link_id from for_each_set_bit with IEEE80211_MLD_MAX_NUM_LINKS bound is guaranteed in-range. link_removal_timeout is stack-allocated with that same size. No counterexample possible.

Finding #5 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 7663
Taint snippetcontrol = le16_to_cpu(prof->control);
Tainted varlink_id
Subscript[] line 7711
Sink snippet(link_removal_timeout[link_id] - 1);
Possibly guardedyes (heuristic)
Dismissed: Same reasoning as findings #3 and #4. This branch is only reached when link_removal_timeout[link_id] >= 1 (line 7707), so the subtraction is also safe from underflow. No counterexample possible.

ieee80211_rx_mgmt_assoc_resp() — net/mac80211/mlme.c FP confidence=high

The scanner misidentifies the flow. 'status_code' from le16_to_cpu() is passed to ieee80211_destroy_assoc_data() as an enum assoc_status argument, not as a loop bound. Inside the callee, the loop at line 5333 iterates over ARRAY_SIZE(data.bss) — a compile-time constant derived from the struct definition — not over status_code. status_code controls only which branch of an if/else is taken (ASSOC_SUCCESS vs other), never the loop iteration count. The loop bound is statically determined.

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

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 7192
Taint snippetstatus_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
Tainted varstatus_code
Call siteline 7357 — passes status_code to ieee80211_destroy_assoc_data()
Call snippetieee80211_destroy_assoc_data(sdata,
Loopfor_loop line 5333
Sink snippetfor (i = 0; i < ARRAY_SIZE(data.bss); i++)
Possibly guardedyes (heuristic)
Dismissed: The taint analysis confused the data-flow path. status_code is indeed server-supplied (le16_to_cpu of a received frame field). It is passed as the second argument to ieee80211_destroy_assoc_data(), which has type enum assoc_status. Inside that function, status_code is used only in conditional comparisons (status != ASSOC_SUCCESS, status != ASSOC_REJECTED) to decide control flow. The for loop at line 5333 iterates 'for (i = 0; i < ARRAY_SIZE(data.bss); i++)' — ARRAY_SIZE is a compile-time constant and is completely independent of the status_code value. No counterexample can be constructed because status_code never touches the loop bound. This is a classic false positive where the taint tracker incorrectly attributed the loop bound taint to a value that only influences branch selection, not iteration count.

ieee80211_rx_mgmt_beacon() — net/mac80211/mlme.c FP confidence=high

All findings are false positives. The core issue is that ieee802_11_parse_elems_full() validates all element pointers and lengths before returning, establishing postconditions that cover all subsequent field accesses. The taint source (le16_to_cpu() of frame_control at line 8082) is used only to initialize parse_params.type, which is a locally-controlled routing value. The actual server-supplied beacon IE data flows through ieee802_11_parse_elems_full() which validates element bounds. Specific findings: #1 is a type analysis error (u8[0] to u8 is not truncation); #2's ssid_len is parser-validated and guarded before use; #3 uses sizeof() which is compile-time; #4-8 all have explicit link_id >= IEEE80211_MLD_MAX_NUM_LINKS bounds checks before array use; #9's ttlm_num is parser-validated to reflect actual parsed element count.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 8340
Taint snippeterp_value = elems->erp_info[0];
Tainted varerp_value
Truncationline 8340: 16 → 8-bit u8
Sink snippeterp_value = elems->erp_info[0];
Possibly guardedno
Dismissed: False positive: elems->erp_info[0] is a u8 array element assigned to u8 erp_value. There is no 16-to-8 bit truncation here. The scanner incorrectly identified this as a widening/narrowing issue. The taint trace claiming le16_to_cpu() at line 8082 (frame_control) propagates to erp_info[0] is implausible — erp_info is a separate parsed element pointer populated by the element parser, not derived from frame_control.

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

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 8082
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 8207 — passes elems to ieee80211_mgd_ssid_mismatch()
Call snippetieee80211_mgd_ssid_mismatch(sdata, elems)) {
Sink (in callee)memcmp() line 8022 (arg 2, role=size)
Sink snippetif (!memcmp(elems->ssid, zero_ssid, elems->ssid_len))
Possibly guardedyes (heuristic)
Dismissed: False positive. ieee802_11_parse_elems_full() validates all element pointers and lengths including ssid and ssid_len. Inside ieee80211_mgd_ssid_mismatch(), there are guards: ssid_len==0 returns false, ssid_len != cfg->ssid_len returns true (without memcmp), so the memcmp at line 8022 is only reached when ssid_len equals cfg->ssid_len which is a locally-controlled value (already validated SSID length). No counterexample possible: any ssid_len that could cause OOB would either be 0 (caught) or differ from cfg->ssid_len (caught) before reaching memcmp.

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

CategoryCat B — server value → size/alloc argument
Taint sourcele16_to_cpu() line 8082
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 8395 — passes elems to ieee80211_config_bw()
Call snippetif (ieee80211_config_bw(link, elems, true, &changed,
Sink (in callee)memcmp() line 1690 (arg 2, role=size)
Sink snippetif (memcmp(&link->conf->tpe, &elems->tpe, sizeof(elems->tpe))) {
Possibly guardedno
Dismissed: False positive. The memcmp sink at line 1690 uses sizeof(elems->tpe) as the size argument, which is a compile-time constant sizeof — not a server-supplied value. The scanner incorrectly flagged a sizeof expression as a tainted size argument. No possible counterexample since sizeof is always safe.

Finding #4 — Category H — cross-function via ieee80211_ml_reconfiguration() — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 8082
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 8418 — passes elems to ieee80211_ml_reconfiguration()
Call snippetieee80211_ml_reconfiguration(sdata, elems);
Truncationline 7664: None → None-bit
Sink snippetlink_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID;
Possibly guardedno
Dismissed: False positive. The narrowing at line 7664 extracts link_id via masking (& IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID), which limits the value to the LINK_ID bit field range. Immediately after, line 7666 checks link_id >= IEEE80211_MLD_MAX_NUM_LINKS and continues (skips) if out of range. The narrowing itself is intentional bit-field extraction, not a vulnerability.

Finding #5 — Category C — cross-function via ieee80211_ml_reconfiguration() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 8082
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 8418 — passes elems to ieee80211_ml_reconfiguration()
Call snippetieee80211_ml_reconfiguration(sdata, elems);
Subscript (in callee)[] line 7682
Sink snippetlink_removal_timeout[link_id] = get_unaligned_le16(pos);
Possibly guardedyes (heuristic)
Dismissed: False positive. At line 7666: if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) continue; This guards the array access at line 7682 (link_removal_timeout[link_id]). The array has IEEE80211_MLD_MAX_NUM_LINKS entries. No counterexample: any link_id >= IEEE80211_MLD_MAX_NUM_LINKS is skipped by the continue statement before reaching the array indexing.

Finding #6 — Category C — cross-function via ieee80211_ml_reconfiguration() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 8082
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 8418 — passes elems to ieee80211_ml_reconfiguration()
Call snippetieee80211_ml_reconfiguration(sdata, elems);
Subscript (in callee)[] line 7699
Sink snippetsdata_dereference(sdata->vif.link_conf[link_id], sdata);
Possibly guardedyes (heuristic)
Dismissed: False positive. Same link_id >= IEEE80211_MLD_MAX_NUM_LINKS guard at line 7666 protects all subsequent uses of link_id as array index within this loop iteration, including sdata->vif.link_conf[link_id]. No counterexample possible given the explicit bounds check with continue.

Finding #7 — Category C — cross-function via ieee80211_ml_reconfiguration() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 8082
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 8418 — passes elems to ieee80211_ml_reconfiguration()
Call snippetieee80211_ml_reconfiguration(sdata, elems);
Subscript (in callee)[] line 7707
Sink snippetif (link_removal_timeout[link_id] < 1)
Possibly guardedyes (heuristic)
Dismissed: False positive. Same guard as findings #5 and #6. link_removal_timeout[link_id] at line 7707 is protected by the bounds check at line 7666 which skips iterations where link_id >= IEEE80211_MLD_MAX_NUM_LINKS.

Finding #8 — Category C — cross-function via ieee80211_ml_reconfiguration() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 8082
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 8418 — passes elems to ieee80211_ml_reconfiguration()
Call snippetieee80211_ml_reconfiguration(sdata, elems);
Subscript (in callee)[] line 7711
Sink snippet(link_removal_timeout[link_id] - 1);
Possibly guardedyes (heuristic)
Dismissed: False positive. Same protection as findings #5, #6, #7. The link_id >= IEEE80211_MLD_MAX_NUM_LINKS check with continue at line 7666 prevents any out-of-bounds link_id from reaching line 7711.

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

CategoryCat F — server value → loop iteration count
Taint sourcele16_to_cpu() line 8082
Taint snippetstruct ieee80211_elems_parse_params parse_params = {
Tainted varelems
Call siteline 8419 — passes elems to ieee80211_process_adv_ttlm()
Call snippetieee80211_process_adv_ttlm(sdata, elems,
Loopfor_loop line 7841
Sink snippetfor (i = 0; i < elems->ttlm_num; i++) {
Possibly guardedno
Dismissed: False positive. elems->ttlm_num and elems->ttlm[] are populated by ieee802_11_parse_elems_full() which validates that ttlm_num TT-LM elements exist within the input buffer. The loop at line 7841 iterates exactly over the parsed elements; ttlm_num reflects the actual count of validated elements stored in the ttlm[] array. The loop bound is inherently safe because the parser bounds-checks during population. Each loop body calls ieee80211_parse_adv_t2l() which performs additional validation.

ieee80211_verify_peer_he_mcs_support() — net/mac80211/mlme.c FP confidence=high

All three findings involve assigning a bitmask-extracted 2-bit field (masked with & 3, yielding values 0-3) from a 16-bit server-supplied value into a u8 variable. The & 3 masking operation strictly limits the assigned value to the range [0,3] before the assignment, making truncation impossible. The scanner's own note explicitly states to flag as false positive when & mask limits the value to destination width — which is exactly the case here. No valid counterexample can be constructed where a 16-bit value shifted and ANDed with 3 would produce a value exceeding u8 range.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 720
Taint snippetu8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
Tainted varap_op_val
Truncationline 720: 16 → 8-bit u8
Sink snippetu8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
Possibly guardedno
Dismissed: The expression `(ap_min_req_set >> (2 * (nss - 1))) & 3` uses `& 3` to mask the result to exactly 2 bits (values 0-3) before assignment to u8. No truncation is possible — cannot construct a counterexample. False positive per the scanner's own masking exception rule.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 727
Taint snippetap_rx_val = (mcs_80_map_rx >> (2 * (nss - 1))) & 3;
Tainted varap_rx_val
Truncationline 727: 16 → 8-bit u8
Sink snippetap_rx_val = (mcs_80_map_rx >> (2 * (nss - 1))) & 3;
Possibly guardedyes (heuristic)
Dismissed: The expression `(mcs_80_map_rx >> (2 * (nss - 1))) & 3` masks to 2 bits before u8 assignment. Result is always in [0,3]. No truncation possible; no counterexample can be constructed.

Finding #3 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 728
Taint snippetap_tx_val = (mcs_80_map_tx >> (2 * (nss - 1))) & 3;
Tainted varap_tx_val
Truncationline 728: 16 → 8-bit u8
Sink snippetap_tx_val = (mcs_80_map_tx >> (2 * (nss - 1))) & 3;
Possibly guardedyes (heuristic)
Dismissed: The expression `(mcs_80_map_tx >> (2 * (nss - 1))) & 3` masks to 2 bits before u8 assignment. Result is always in [0,3]. No truncation possible; no counterexample can be constructed.

ieee80211_verify_sta_he_mcs_support() — net/mac80211/mlme.c FP confidence=high

All three findings involve extracting 2-bit fields from 16-bit MCS maps using right-shift and '& 3' masking. The result is always in [0,3], which fits trivially in u8. The scanner note itself says to flag as false positive when masking limits the value to the destination width — that condition is satisfied here. No truncation loss is possible regardless of the server-supplied 16-bit input values.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 787
Taint snippetu8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3;
Tainted varsta_rx_val
Truncationline 787: 16 → 8-bit u8
Sink snippetu8 sta_rx_val = (sta_mcs_map_rx >> (2 * (nss - 1))) & 3;
Possibly guardedno
Dismissed: The expression '(sta_mcs_map_rx >> (2 * (nss - 1))) & 3' uses '& 3' to mask the result to exactly 2 bits (values 0-3). No 16-bit input can produce a value outside [0,3] after this masking, so assigning to u8 is safe. No counterexample exists.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 788
Taint snippetu8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3;
Tainted varsta_tx_val
Truncationline 788: 16 → 8-bit u8
Sink snippetu8 sta_tx_val = (sta_mcs_map_tx >> (2 * (nss - 1))) & 3;
Possibly guardedno
Dismissed: The expression '(sta_mcs_map_tx >> (2 * (nss - 1))) & 3' uses '& 3' to mask the result to exactly 2 bits (values 0-3). No 16-bit input can produce a value outside [0,3] after this masking, so assigning to u8 is safe. No counterexample exists.

Finding #3 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 789
Taint snippetu8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
Tainted varap_val
Truncationline 789: 16 → 8-bit u8
Sink snippetu8 ap_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
Possibly guardedno
Dismissed: The expression '(ap_min_req_set >> (2 * (nss - 1))) & 3' uses '& 3' to mask the result to exactly 2 bits (values 0-3). ap_min_req_set comes from le16_to_cpu(he_op->he_mcs_nss_set) (AP-supplied), but after masking, the value is always in [0,3], safely fitting in u8. No counterexample exists.

ieee80211_verify_sta_vht_mcs_support() — net/mac80211/mlme.c FP confidence=high

All three flagged truncations are safe because the RHS expression applies '& 3' masking before assignment to u8, limiting the value to {0,1,2,3} regardless of the 16-bit source width. No counterexample can be constructed where a value passes the mask yet exceeds u8 range. Findings #2 and #3 also involve locally-copied station capabilities rather than raw server-supplied data.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 634
Taint snippetu8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
Tainted varap_op_val
Truncationline 634: 16 → 8-bit u8
Sink snippetu8 ap_op_val = (ap_min_req_set >> (2 * (nss - 1))) & 3;
Possibly guardedno
Dismissed: The expression '(ap_min_req_set >> (2 * (nss - 1))) & 3' applies '& 3' before assignment to u8. The maximum possible value is 3, which fits trivially in u8. No counterexample exists: any 16-bit input after right-shift and '& 3' yields a value in [0,3], well within u8 range. The truncation is safe.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 641
Taint snippetsta_rx_val = (sta_rx_mcs_map >> (2 * (nss - 1))) & 3;
Tainted varsta_rx_val
Truncationline 641: 16 → 8-bit u8
Sink snippetsta_rx_val = (sta_rx_mcs_map >> (2 * (nss - 1))) & 3;
Possibly guardedno
Dismissed: sta_rx_mcs_map comes from a local copy of the station's own VHT capabilities (sband->vht_cap, then overridden by ieee80211_apply_vhtcap_overrides), not from the server's VHT operation. Additionally, '& 3' masks the result to [0,3] before u8 assignment — no truncation issue is possible.

Finding #3 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 642
Taint snippetsta_tx_val = (sta_tx_mcs_map >> (2 * (nss - 1))) & 3;
Tainted varsta_tx_val
Truncationline 642: 16 → 8-bit u8
Sink snippetsta_tx_val = (sta_tx_mcs_map >> (2 * (nss - 1))) & 3;
Possibly guardedno
Dismissed: sta_tx_mcs_map comes from the same locally-copied station VHT capability structure, not server-supplied. The '& 3' mask limits the value to [0,3] before u8 assignment. No truncation issue possible; false positive.

ieee80211_rx_h_ctrl() — net/mac80211/rx.c FP confidence=high

The function reads a BAR control field from a received 802.11 frame via skb_copy_bits(). The tid value is extracted as (u16 >> 12), which constrains it to [0, 15]. The tid_rx array has IEEE80211_NUM_TIDS=16 elements (indices 0-15), so no out-of-bounds access is possible. No counterexample exists. The scanner flagged a le16_to_cpu result without recognising that the subsequent right-shift by 12 eliminates all risk.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 3395
Taint snippettid = le16_to_cpu(bar_data.control) >> 12;
Tainted vartid
Subscript[] line 3405
Sink snippettid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]);
Possibly guardedno
Dismissed: tid = le16_to_cpu(bar_data.control) >> 12 yields a value in [0, 15]. tid_rx[] has IEEE80211_NUM_TIDS=16 entries, so valid indices are [0, 15]. No counterexample can be constructed — the 4-bit result cannot exceed 15, and the array bound is 16. This is a false positive from the static analyser not tracking the effect of the >> 12 shift on a u16.

ieee80211_rx_h_defragment() — net/mac80211/rx.c FP confidence=high

The scanner incorrectly traces taint from le16_to_cpu(hdr->seq_ctrl) through 'entry' to the memcpy destinations inside pskb_expand_head(). In reality: (1) 'entry' is a pointer to a fixed-size struct within a bounded cache array, not an arbitrary server-controlled pointer; (2) pskb_expand_head() is called with entry->extra_len as the 'ntail' size parameter, not as a pointer; (3) the memcpy destinations inside pskb_expand_head() are 'data' (freshly kmalloc'd) and skb internals — neither is derived from the tainted value; (4) entry->extra_len accumulates actual skb->len values of received fragments, bounded by real MTU constraints, not a raw unchecked header field.

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

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 2390
Taint snippetsc = le16_to_cpu(hdr->seq_ctrl);
Tainted varentry
Call siteline 2513 — passes entry to pskb_expand_head()
Call snippetif (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
Sink (in callee)memcpy() line 2320 (arg 0, role=pointer)
Sink snippetmemcpy(data + nhead, skb->head, skb_tail_pointer(skb) - skb->head);
Possibly guardedyes (heuristic)
Dismissed: The scanner misattributes the memcpy destination pointer (arg 0) as tainted. The memcpy at pskb_expand_head:2320 copies from skb->head to 'data' (a freshly allocated buffer). Neither 'data' nor the copy length (skb_tail_pointer(skb)-skb->head) is derived from entry->extra_len or sc. The 'entry' pointer itself is a valid struct pointer from a bounded cache array, and entry->extra_len is accumulated from actual skb->len values. No counterexample can be constructed where sc values cause an OOB memcpy at line 2320 — the memcpy size is derived from skb internal pointers, not from the tainted field.

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

CategoryCat A — server offset → pointer → memory op
Taint sourcele16_to_cpu() line 2390
Taint snippetsc = le16_to_cpu(hdr->seq_ctrl);
Tainted varentry
Call siteline 2513 — passes entry to pskb_expand_head()
Call snippetif (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
Sink (in callee)memcpy() line 2322 (arg 0, role=pointer)
Sink snippetmemcpy((struct skb_shared_info *)(data + size),
Possibly guardedyes (heuristic)
Dismissed: Same reasoning as finding #1. The memcpy at pskb_expand_head:2322 copies skb_shinfo data into (data+size) where 'size' = osize + 0 + ntail, with ntail=entry->extra_len. The destination pointer is 'data+size' (within the kmalloc'd region) and the source/size come from skb_shinfo(skb)->nr_frags — not from the tainted 'sc' value. The scanner incorrectly identifies the memcpy destination as tainted. No valid counterexample exists where seq_ctrl values cause this specific memcpy to be unsafe.

ieee80211_sta_nss_capability() — net/mac80211/sta_info.c FP confidence=high

All three findings involve extracting 2-bit fields via '& 3' from a 16-bit le16_to_cpu() result and assigning to u8. The masking to 2 bits (values 0-3) ensures no information loss when stored in u8. The scanner's own note says to flag as false positive when the RHS uses masking that limits the value to the destination width, which is exactly the case here. Additionally, the extracted values are only used in equality comparisons (against MCS_NOT_SUPPORTED sentinel values) or to set a small loop index (i+1, max 8), with no array indexing, allocation sizing, or other dangerous sink.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 3485
Taint snippetu8 mcs_160 = (mcs_160_map >> (2 * i)) & 3;
Tainted varmcs_160
Truncationline 3485: 16 → 8-bit u8
Sink snippetu8 mcs_160 = (mcs_160_map >> (2 * i)) & 3;
Possibly guardedno
Dismissed: The expression '(mcs_160_map >> (2 * i)) & 3' masks to exactly 2 bits before assignment to u8. Values 0-3 fit trivially in u8. No counterexample can be constructed: the maximum post-mask value is 3, well within u8 range. The value is only compared to IEEE80211_HE_MCS_NOT_SUPPORTED (a 2-bit constant). False positive per the scanner's own masking criterion.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 3493
Taint snippetu8 mcs_80 = (mcs_80_map >> (2 * i)) & 3;
Tainted varmcs_80
Truncationline 3493: 16 → 8-bit u8
Sink snippetu8 mcs_80 = (mcs_80_map >> (2 * i)) & 3;
Possibly guardedno
Dismissed: Identical pattern to finding #1. '(mcs_80_map >> (2 * i)) & 3' masks to 2 bits before u8 assignment. Maximum value is 3. No dangerous sink; only used in a comparison. False positive.

Finding #3 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 3529
Taint snippetu8 mcs = (rx_mcs_map >> (2 * i)) & 3;
Tainted varmcs
Truncationline 3529: 16 → 8-bit u8
Sink snippetu8 mcs = (rx_mcs_map >> (2 * i)) & 3;
Possibly guardedno
Dismissed: Same pattern: '(rx_mcs_map >> (2 * i)) & 3' masks to 2 bits before u8 assignment. Maximum value is 3. Used only in a comparison against IEEE80211_VHT_MCS_NOT_SUPPORTED. False positive.

__ieee80211_tx_status() — net/mac80211/status.c FP confidence=high

All three findings are false positives. For #1 and #2: tid at the array sinks (lines 1077/1079) is guarded by ieee80211_is_data_present(fc), while the BAR-derived tid (from le16_to_cpu) is set under ieee80211_is_back_req(fc) — a control frame, not a data frame — making these paths mutually exclusive. When the sinks are reachable, tid comes from qc[0] & 0xf which is bounded to 0-15. For #3: the BAR TID field is 4 bits (IEEE80211_BAR_CTRL_TID_INFO_MASK/SHIFT gives 0-15), and tid_tx[] has IEEE80211_NUM_TIDS=16 entries, so no OOB is possible.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 1060
Taint snippetcontrol = le16_to_cpu(bar->control);
Tainted vartid
Subscript[] line 1077
Sink snippetsta->deflink.status_stats.msdu_failed[tid]++;
Possibly guardedno
Dismissed: The sink at line 1077 is under ieee80211_is_data_present(fc). The BAR-derived tid is set only when ieee80211_is_back_req(fc) is true, which is a control frame — ieee80211_is_data_present() will be false for that frame type. So the tainted tid never reaches the sink. When the sink IS reachable, tid = qc[0] & 0xf (0-15), which is in bounds for msdu_failed[] sized IEEE80211_NUM_TIDS=16. No counterexample possible.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 1060
Taint snippetcontrol = le16_to_cpu(bar->control);
Tainted vartid
Subscript[] line 1079
Sink snippetsta->deflink.status_stats.msdu_retries[tid] +=
Possibly guardedno
Dismissed: Same reasoning as finding #1. The sink at line 1079 is under ieee80211_is_data_present(fc), which is mutually exclusive with the BAR path. When reachable, tid = qc[0] & 0xf (0-15), within bounds.

Finding #3 — Category C — cross-function via ieee80211_set_bar_pending() — false positive

CategoryCat C — server value → array subscript
Taint sourcele16_to_cpu() line 1060
Taint snippetcontrol = le16_to_cpu(bar->control);
Tainted vartid
Call siteline 1068 — passes tid to ieee80211_set_bar_pending()
Call snippetieee80211_set_bar_pending(sta, tid, ssn);
Subscript (in callee)[] line 201
Sink snippettid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
Possibly guardedno
Dismissed: IEEE80211_BAR_CTRL_TID_INFO_MASK is 0xF000 and IEEE80211_BAR_CTRL_TID_INFO_SHIFT is 12, so (control & mask) >> shift yields 0-15. sta->ampdu_mlme.tid_tx[] is sized IEEE80211_NUM_TIDS=16 (indices 0-15). No out-of-bounds access is possible. No counterexample can be constructed.

tkip_mixing_phase1() — net/mac80211/tkip.c FP confidence=high

All five findings are false positives. The taint source 'tk' is TKIP temporal key material stored in kernel-local key structures (key->conf.key[]), not a server/network-supplied value. The 'ta' parameter is a 6-byte MAC address and 'tsc_IV32' is a u32 counter. More critically, tkipS() masks its u16 argument with '& 0xff' and '>> 8' before indexing tkip_sbox[], guaranteeing both subscripts are in [0,255] — which is exactly the valid range for the 256-entry sbox — regardless of the input value. No counterexample can be constructed that produces an out-of-bounds access, because the masking is complete for a u16 input.

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

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 96
Taint snippetp1k[0] += tkipS(p1k[4] ^ get_unaligned_le16(tk + 0 + j));
Tainted varp1k[4] ^ get_unaligned_le16(tk + 0 + j)
Call siteline 96 — passes p1k[4] ^ get_unaligned_le16(tk + 0 + j) to tkipS()
Call snippetp1k[0] += tkipS(p1k[4] ^ get_unaligned_le16(tk + 0 + j));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: tk is local key material, not a network packet field. tkipS() uses 'val & 0xff' and 'val >> 8' — both always in [0,255] for any u16 input. No counterexample possible; array access is unconditionally safe.

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

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 97
Taint snippetp1k[1] += tkipS(p1k[0] ^ get_unaligned_le16(tk + 4 + j));
Tainted varp1k[0] ^ get_unaligned_le16(tk + 4 + j)
Call siteline 97 — passes p1k[0] ^ get_unaligned_le16(tk + 4 + j) to tkipS()
Call snippetp1k[1] += tkipS(p1k[0] ^ get_unaligned_le16(tk + 4 + j));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: Same reasoning as finding #1. XOR of two u16 values is u16; masking in tkipS() constrains both indices to [0,255]. False positive.

Finding #3 — Category C — cross-function via tkipS() — false positive

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 98
Taint snippetp1k[2] += tkipS(p1k[1] ^ get_unaligned_le16(tk + 8 + j));
Tainted varp1k[1] ^ get_unaligned_le16(tk + 8 + j)
Call siteline 98 — passes p1k[1] ^ get_unaligned_le16(tk + 8 + j) to tkipS()
Call snippetp1k[2] += tkipS(p1k[1] ^ get_unaligned_le16(tk + 8 + j));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: Same reasoning as finding #1. False positive.

Finding #4 — Category C — cross-function via tkipS() — false positive

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 99
Taint snippetp1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j));
Tainted varp1k[2] ^ get_unaligned_le16(tk + 12 + j)
Call siteline 99 — passes p1k[2] ^ get_unaligned_le16(tk + 12 + j) to tkipS()
Call snippetp1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: Same reasoning as finding #1. False positive.

Finding #5 — Category C — cross-function via tkipS() — false positive

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 100
Taint snippetp1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;
Tainted varp1k[3] ^ get_unaligned_le16(tk + 0 + j)
Call siteline 100 — passes p1k[3] ^ get_unaligned_le16(tk + 0 + j) to tkipS()
Call snippetp1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: Same reasoning as finding #1. False positive.

tkip_mixing_phase2() — net/mac80211/tkip.c FP confidence=high

All findings are false positives. The tkipS() function receives a u16 argument and uses it as two array indices: (val & 0xff) and (val >> 8). Both expressions are mathematically constrained to [0, 255] regardless of the input value — 'val & 0xff' masks to 8 bits, and 'val >> 8' on a u16 also yields at most 8 bits. The tkip_sbox[] array has exactly 256 entries, so no OOB access is possible. The static scanner flagged 'tainted u16 used as array subscript' without recognizing that the masking and shifting make the index safe by construction. No counterexample exists because no u16 value can produce an index outside [0,255] through these operations.

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

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 120
Taint snippetppk[0] += tkipS(ppk[5] ^ get_unaligned_le16(tk + 0));
Tainted varppk[5] ^ get_unaligned_le16(tk + 0)
Call siteline 120 — passes ppk[5] ^ get_unaligned_le16(tk + 0) to tkipS()
Call snippetppk[0] += tkipS(ppk[5] ^ get_unaligned_le16(tk + 0));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: tkipS() masks val to 8-bit indices: (val & 0xff) ∈ [0,255] and (val >> 8) ∈ [0,255]. tkip_sbox has 256 entries. No OOB possible regardless of val's value. Counterexample: no u16 value produces index > 255 through these operations.

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

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 121
Taint snippetppk[1] += tkipS(ppk[0] ^ get_unaligned_le16(tk + 2));
Tainted varppk[0] ^ get_unaligned_le16(tk + 2)
Call siteline 121 — passes ppk[0] ^ get_unaligned_le16(tk + 2) to tkipS()
Call snippetppk[1] += tkipS(ppk[0] ^ get_unaligned_le16(tk + 2));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: Same reasoning as finding #1. The u16 XOR result passed to tkipS() is always bounded to [0,65535], and tkipS() internally masks to [0,255] for both accesses. No counterexample possible.

Finding #3 — Category C — cross-function via tkipS() — false positive

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 122
Taint snippetppk[2] += tkipS(ppk[1] ^ get_unaligned_le16(tk + 4));
Tainted varppk[1] ^ get_unaligned_le16(tk + 4)
Call siteline 122 — passes ppk[1] ^ get_unaligned_le16(tk + 4) to tkipS()
Call snippetppk[2] += tkipS(ppk[1] ^ get_unaligned_le16(tk + 4));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: Same reasoning as finding #1. tkipS() masks u16 to safe [0,255] indices unconditionally.

Finding #4 — Category C — cross-function via tkipS() — false positive

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 123
Taint snippetppk[3] += tkipS(ppk[2] ^ get_unaligned_le16(tk + 6));
Tainted varppk[2] ^ get_unaligned_le16(tk + 6)
Call siteline 123 — passes ppk[2] ^ get_unaligned_le16(tk + 6) to tkipS()
Call snippetppk[3] += tkipS(ppk[2] ^ get_unaligned_le16(tk + 6));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: Same reasoning as finding #1. tkipS() masks u16 to safe [0,255] indices unconditionally.

Finding #5 — Category C — cross-function via tkipS() — false positive

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 124
Taint snippetppk[4] += tkipS(ppk[3] ^ get_unaligned_le16(tk + 8));
Tainted varppk[3] ^ get_unaligned_le16(tk + 8)
Call siteline 124 — passes ppk[3] ^ get_unaligned_le16(tk + 8) to tkipS()
Call snippetppk[4] += tkipS(ppk[3] ^ get_unaligned_le16(tk + 8));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: Same reasoning as finding #1. tkipS() masks u16 to safe [0,255] indices unconditionally.

Finding #6 — Category C — cross-function via tkipS() — false positive

CategoryCat C — server value → array subscript
Taint sourceget_unaligned_le16() line 125
Taint snippetppk[5] += tkipS(ppk[4] ^ get_unaligned_le16(tk + 10));
Tainted varppk[4] ^ get_unaligned_le16(tk + 10)
Call siteline 125 — passes ppk[4] ^ get_unaligned_le16(tk + 10) to tkipS()
Call snippetppk[5] += tkipS(ppk[4] ^ get_unaligned_le16(tk + 10));
Subscript (in callee)[] line 64
Sink snippetreturn tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
Possibly guardedno
Dismissed: Same reasoning as finding #1. tkipS() masks u16 to safe [0,255] indices unconditionally.

ieee80211_apply_vhtcap_overrides() — net/mac80211/vht.c FP confidence=high

All four findings are false positives. The scanner correctly identifies 16-bit to 8-bit truncation, but misses that the bitwise AND with IEEE80211_VHT_MCS_NOT_SUPPORTED (value=3, i.e., 0x3) limits any result to at most 2 bits (values 0-3) before assignment to u8. No truncation of meaningful bits can occur. Additionally, the mask/capa fields from sdata->u.mgd are user-space configured overrides (via nl80211), not server-supplied network data, further reducing concern.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 91
Taint snippetm = (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
Tainted varm
Truncationline 91: 16 → 8-bit u8
Sink snippetm = (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
Possibly guardedno
Dismissed: rxmcs_mask comes from sdata->u.mgd.vht_capa_mask (user nl80211 config, not server). The expression (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED masks to 2 bits (max value 3), which trivially fits in u8. No counterexample exists that could cause truncation of meaningful bits.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 93
Taint snippetc = (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
Tainted varc
Truncationline 93: 16 → 8-bit u8
Sink snippetc = (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
Possibly guardedno
Dismissed: rxmcs_cap comes from vht_cap->vht_mcs.rx_mcs_map (AP/server-supplied). However, (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED masks to exactly 2 bits (values 0-3). No 16-bit value, regardless of what the server sends, can produce a result exceeding 3 after this mask. The truncation to u8 is entirely safe. No counterexample is constructible.

Finding #3 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 101
Taint snippetm = (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
Tainted varm
Truncationline 101: 16 → 8-bit u8
Sink snippetm = (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
Possibly guardedno
Dismissed: txmcs_mask comes from sdata->u.mgd.vht_capa_mask (user nl80211 config, not server). The expression (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED masks to 2 bits (max value 3), fitting trivially in u8. No counterexample exists.

Finding #4 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 103
Taint snippetc = (txmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
Tainted varc
Truncationline 103: 16 → 8-bit u8
Sink snippetc = (txmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
Possibly guardedno
Dismissed: txmcs_cap comes from vht_cap->vht_mcs.tx_mcs_map (AP/server-supplied). Same analysis as finding #2: the & IEEE80211_VHT_MCS_NOT_SUPPORTED mask (value=3) limits any 16-bit input to a 2-bit result before u8 assignment. No counterexample is constructible.

mctp_ioctl_tag_copy_from_user() — net/mctp/af_mctp.c FP confidence=high

The `size` variable in mctp_ioctl_tag_copy_from_user() is NOT user-supplied — it is derived entirely from compile-time sizeof() expressions. The taint analysis has misidentified copy_from_user() as a taint source for the `size` argument, but `size` is set to either sizeof(*ctl) (i.e., sizeof(struct mctp_ioc_tag_ctl2)) or sizeof(ctl_compat) (i.e., sizeof(struct mctp_ioc_tag_ctl)), both of which are kernel-internal constants determined at compile time. The `arg` (user pointer) is only used as the source address for the copy, not as the size. The destination buffers (`ctl` passed by pointer from callers, or the local `ctl_compat`) are stack-allocated with matching sizes. There is no user-controlled size in this function whatsoever.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 451
Taint snippetrc = copy_from_user(ptr, (void __user *)arg, size);
Tainted varsize
Unvalidated sizecopy_from_user() arg 2 line 451 — size size
Sink snippetrc = copy_from_user(ptr, (void __user *)arg, size);
Possibly guardedno
Dismissed: The `size` variable is set exclusively from sizeof() of kernel-defined structs (either sizeof(struct mctp_ioc_tag_ctl2) or sizeof(struct mctp_ioc_tag_ctl)), making it a compile-time constant — not user-supplied data. The copy_from_user() call uses `arg` only as the user-space source address, not as the size. The destination buffers are stack-allocated with exactly the matching size. No counterexample can be constructed where a user-controlled value reaches the size argument. This is a false positive from the taint analysis incorrectly propagating taint from copy_from_user() itself back onto the `size` parameter.

mctp_ioctl_tag_copy_to_user() — net/mctp/af_mctp.c FP confidence=high

The `size` variable in `mctp_ioctl_tag_copy_to_user()` is not user-controlled at all. It is set to either `sizeof(*ctl)` (a compile-time constant for `struct mctp_ioc_tag_ctl2`) or `sizeof(ctl_compat)` (a compile-time constant for `struct mctp_ioc_tag_ctl`), depending on the boolean `tagv2` parameter. Both values are fixed kernel-internal sizes determined at compile time. The `ctl` struct passed in is a locally-allocated stack variable in `mctp_ioctl_alloctag()`, filled by `mctp_ioctl_tag_copy_from_user()` and then modified by the kernel (e.g., `ctl.tag = tag | MCTP_TAG_OWNER | MCTP_TAG_PREALLOC`). No user-supplied size is ever used; the copy_to_user call copies a fixed-size kernel struct to userspace. The scanner's concern about an unvalidated user-controlled size is entirely unfounded here.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 495
Taint snippetrc = copy_to_user((void __user *)arg, ptr, size);
Tainted varsize
Unvalidated sizecopy_to_user() arg 2 line 495 — size size
Sink snippetrc = copy_to_user((void __user *)arg, ptr, size);
Possibly guardedno
Dismissed: The `size` variable is set to `sizeof(*ctl)` or `sizeof(ctl_compat)`, both compile-time constants. No user-controlled size is ever involved. The scanner appears to have confused the user-space destination address `arg` (which is user-supplied) with the size argument. The size is purely kernel-internal and fixed. No counterexample can be constructed because there is no dynamic size computation at all — the value is always one of two compile-time constants.

mptcp_get_subflow_data() — net/mptcp/sockopt.c FP confidence=high

The function has solid validation discipline. The copylen variable is capped by min_t(unsigned int, len, sizeof(*sfd)), where sizeof(*sfd) is a compile-time constant equal to the destination buffer size. The guard at line 1094 ensures len >= MIN_INFO_OPTLEN_SIZE, and BUILD_BUG_ON enforces sizeof(*sfd) == MIN_INFO_OPTLEN_SIZE. Thus copylen is always in [MIN_INFO_OPTLEN_SIZE, sizeof(*sfd)], exactly fitting the destination stack buffer. Additional validation of sfd->size_subflow_data and sfd->size_user fields follows the copy.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 1100
Taint snippetif (copy_from_user(sfd, optval, copylen))
Tainted varcopylen
Unvalidated sizecopy_from_user() arg 2 line 1100 — size copylen
Sink snippetif (copy_from_user(sfd, optval, copylen))
Possibly guardedno
Dismissed: copylen = min_t(unsigned int, len, sizeof(*sfd)) caps the copy size at sizeof(*sfd), which is exactly the size of the destination stack buffer sfd. The prior check len >= MIN_INFO_OPTLEN_SIZE combined with BUILD_BUG_ON(sizeof(*sfd) != MIN_INFO_OPTLEN_SIZE) ensures copylen is always within [MIN_INFO_OPTLEN_SIZE, sizeof(*sfd)]. No counterexample can be constructed where copylen exceeds the destination buffer size — the bounds check is tight and sufficient.

mptcp_put_full_info() — net/mptcp/sockopt.c FP confidence=high

The 'copylen' variable is not user-controlled in a dangerous sense. In the caller, it is computed as min_t(unsigned int, len, sizeof(struct mptcp_info)), which clamps it to a kernel compile-time constant. After adding MIN_FULL_INFO_OPTLEN_SIZE (another constant), the total cannot exceed sizeof(struct mptcp_full_info), which is the size of the local kernel struct 'mfi' being copied. There is no path where a user can supply an arbitrary size that causes OOB access of the source buffer. The taint originates from user-supplied optlen but is immediately clamped by a min() against a kernel constant before being used as the copy size.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 1303
Taint snippetif (copy_to_user(optval, mfi, copylen))
Tainted varcopylen
Unvalidated sizecopy_to_user() arg 2 line 1303 — size copylen
Sink snippetif (copy_to_user(optval, mfi, copylen))
Possibly guardedno
Dismissed: copylen in the caller is computed as min_t(unsigned int, len, sizeof(struct mptcp_info)), clamping any user-supplied length to sizeof(struct mptcp_info). After adding MIN_FULL_INFO_OPTLEN_SIZE, the maximum total is sizeof(struct mptcp_info) + MIN_FULL_INFO_OPTLEN_SIZE, which is within sizeof(struct mptcp_full_info) (the local stack struct). No counterexample exists: no user-supplied value can produce a copylen that exceeds the source buffer size. The scanner flagged it because the original len came from user space, but the min_t() clamp makes it safe.

mptcp_put_subflow_data() — net/mptcp/sockopt.c FP confidence=high

mptcp_put_subflow_data() computes copylen as min(sfd->size_subflow_data, sizeof(*sfd)). Even though size_subflow_data is user-supplied (read in mptcp_get_subflow_data()), the min_t() clamps copylen to at most sizeof(*sfd), which is a compile-time constant equal to the size of the source kernel struct. The copy_to_user() reads from a kernel stack buffer of exactly sizeof(*sfd) bytes, so no out-of-bounds kernel memory read is possible regardless of the user-supplied value.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 1074
Taint snippetif (copy_to_user(optval, sfd, copylen))
Tainted varcopylen
Unvalidated sizecopy_to_user() arg 2 line 1074 — size copylen
Sink snippetif (copy_to_user(optval, sfd, copylen))
Possibly guardedno
Dismissed: copylen = min_t(u32, sfd->size_subflow_data, sizeof(*sfd)). Even with a maximally adversarial user-supplied size_subflow_data (e.g., UINT32_MAX), copylen is clamped to sizeof(*sfd) by min_t. The copy_to_user() source is the kernel stack struct sfd of size sizeof(*sfd), so no kernel-side OOB read occurs. No counterexample can be constructed that bypasses min_t and causes OOB. False positive.

ip_set_sockfn_get() — net/netfilter/ipset/ip_set_core.c FP confidence=high

The function allocates `data = vmalloc(*len)` and saves `copylen = *len` at entry. Every code path that reaches the `copy:` label first validates `*len` with an exact equality check against the expected struct size (e.g., `if (*len != sizeof(struct ip_set_req_get_set))`), ensuring `copylen` equals the allocation size. The copy_to_user at line 2365 therefore cannot exceed the allocated buffer. The scanner flagged `copylen` as unvalidated, but the per-case exact-size guards are sufficient.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 2365
Taint snippetif (copy_to_user(user, data, copylen))
Tainted varcopylen
Unvalidated sizecopy_to_user() arg 2 line 2365 — size copylen
Sink snippetif (copy_to_user(user, data, copylen))
Possibly guardedno
Dismissed: copylen = *len at line 2259; vmalloc(*len) at line 2270 allocates exactly that many bytes. Every switch case reaching `copy:` enforces `*len == sizeof(specific_struct)` via exact equality, so copylen equals the buffer size at the copy_to_user call. No counterexample exists: any value of *len that passes a case's size check is also the exact allocation size. False positive.

hash_ip4_uadt() — net/netfilter/ipset/ip_set_hash_ip.c FP confidence=high

The function validates user-supplied netlink attributes properly before use. The loop at line 154 has a per-iteration counter check (i > IPSET_MAX_RANGE) that caps the maximum number of iterations regardless of the ip/ip_to values. The tainted 'ip' variable from ntohl(h->next.ip) is not used as a buffer index — it is an IP address value passed to adtfn(). Additionally, h->next.ip was written by the kernel itself in a prior call via hash_ip4_data_next(), making it internally computed rather than directly server-supplied from a network buffer.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 153
Taint snippetip = ntohl(h->next.ip);
Tainted varip
Loopfor_loop line 154
Sink snippetfor (; ip <= ip_to; i++) {
Possibly guardedno
Dismissed: The per-iteration guard 'if (i > IPSET_MAX_RANGE) return -ERANGE' at line 156 caps loop iterations at IPSET_MAX_RANGE+1 regardless of ip/ip_to values — criterion (b) is fully satisfied. No counterexample can be constructed: any ip <= ip_to range will be cut off by the iteration counter. Furthermore, h->next.ip is written by the kernel itself (hash_ip4_data_next sets it to a previously-validated e.ip value from a prior call), so it is not directly server-supplied from a network response. The variable 'ip' is also not used as a memory buffer index; it is an IP address value passed as a struct field to adtfn().

hash_ipmark4_uadt() — net/netfilter/ipset/ip_set_hash_ipmark.c FP confidence=high

The loop iterates over IPv4 addresses in a user-specified range, calling adtfn() per address. The tainted `ip` value from ntohl(h->next.ip) is a saved IP address (not a buffer index), and the loop has a per-iteration guard `if (i > IPSET_MAX_RANGE)` that limits iterations. No buffer is indexed by `ip`; there is no OOB memory access possible from this loop structure.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 152
Taint snippetip = ntohl(h->next.ip);
Tainted varip
Loopfor_loop line 153
Sink snippetfor (; ip <= ip_to; i++) {
Possibly guardedno
Dismissed: The scanner flagged `ip` controlling the loop iteration count, but `ip` here is an IPv4 address used only to drive iteration over an IP range — it is never used as a buffer index or allocation size. The per-iteration check `if (i > IPSET_MAX_RANGE)` (line 155) limits the total number of iterations regardless of the IP range size, providing sufficient protection against excessive looping. Counterexample construction: any value of `ip` from `h->next.ip` either exceeds `ip_to` (loop runs 0 times) or is within range (loop bounded by IPSET_MAX_RANGE). No memory corruption path exists.

hash_ipport4_uadt() — net/netfilter/ipset/ip_set_hash_ipport.c FP confidence=high

Both findings are false positives. First, h->next is kernel-internal state written by hash_ipport4_data_next() in a previous iteration — not a server-supplied network buffer. The ntohl()/ntohs() calls on h->next.ip and h->next.port are endian conversions of kernel-written values, not external data. Second, neither 'ip' nor 'p' index into a memory buffer; they iterate over address/port space calling adtfn(). Third, the inner loop body has an explicit IPSET_MAX_RANGE guard (line 195) that limits total iterations regardless of starting values. Finally, the outer loop is bounded by ip_to and the inner loop by port_to, both of which are u32/u16 range-limited values.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 188
Taint snippetip = ntohl(h->next.ip);
Tainted varip
Loopfor_loop line 189
Sink snippetfor (; ip <= ip_to;) {
Possibly guardedno
Dismissed: h->next.ip is written by hash_ipport4_data_next() with a kernel-computed htonl(ip) value. The outer loop is bounded by ip_to (a u32 ceiling). The inner loop has an IPSET_MAX_RANGE check. No buffer is indexed by ip — it's used only as a value to construct e.ip and call adtfn(). Cannot construct a counterexample where ip causes OOB access because no buffer indexing occurs.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 190
Taint snippetp = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
Tainted varp
Loopfor_loop line 192
Sink snippetfor (; p <= port_to; p++, i++) {
Possibly guardedno
Dismissed: h->next.port is written by hash_ipport4_data_next() with a kernel-computed htons(p) value. The inner loop is bounded by port_to (u16 range). The IPSET_MAX_RANGE check at line 195 limits total iterations across all passes. p is used only as a value to construct e.port via htons(p) and call adtfn() — no buffer indexing occurs. Cannot construct a counterexample causing OOB.

hash_ipport6_uadt() — net/netfilter/ipset/ip_set_hash_ipport.c FP confidence=high

The function validates protocol attributes before the loop. The loop iterates over a port range (u16 values, max 65535 iterations) calling adtfn per port. The loop counter 'port' is never used as an array index or allocation size — it only controls how many times adtfn is called with a specific port value written to a local stack struct. h->next.port is internal kernel bookkeeping state (set when retrying), not a server-supplied network value. Even if adversarially controlled, u16 port values bound the loop to at most 65535 iterations with no memory safety impact.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 351
Taint snippetport = ntohs(h->next.port);
Tainted varport
Loopfor_loop line 352
Sink snippetfor (; port <= port_to; port++) {
Possibly guardedno
Dismissed: h->next.port is the kernel's own internal retry-state field, not a server/network-supplied value. More importantly, the loop counter 'port' is a u16-ranged port number that never indexes into any buffer or allocation — it only controls how many calls to adtfn are made, each operating on a local stack struct 'e'. The scanner misidentified port-range iteration as a buffer-bounds problem. No counterexample can be constructed that causes OOB memory access because no array/buffer indexing with 'port' exists.

hash_ipportip4_uadt() — net/netfilter/ipset/ip_set_hash_ipportip.c FP confidence=high

Both flagged taint sources (h->next.ip and h->next.port) are kernel-internally written values, set during a previous call when IPSET_MAX_RANGE was hit. They represent resume points, not network-supplied data. The loops do not index into a buffer — they call adtfn() with element values. The loops are bounded by ip<=ip_to and p<=port_to (validated ranges) plus the per-iteration IPSET_MAX_RANGE check on counter i. No OOB memory access is possible.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 184
Taint snippetip = ntohl(h->next.ip);
Tainted varip
Loopfor_loop line 185
Sink snippetfor (; ip <= ip_to;) {
Possibly guardedno
Dismissed: h->next.ip is written by the kernel itself (hash_ipportip4_data_next stores e.ip which was htonl(ip) where ip was already within the validated [ip,ip_to] range). The ntohl() here is purely an endian round-trip of a kernel-written value. The loop is bounded by ip<=ip_to. No counterexample can be constructed because ip is constrained to the already-validated ip_to bound.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 186
Taint snippetp = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
Tainted varp
Loopfor_loop line 188
Sink snippetfor (; p <= port_to; p++, i++) {
Possibly guardedno
Dismissed: h->next.port is written by the kernel itself (stores e.port = htons(p) where p was within [port, port_to]). The ntohs() is a round-trip of a kernel-written value. The inner loop is bounded by p<=port_to (u16 range, max 65535) and the combined i>IPSET_MAX_RANGE guard. No counterexample can be constructed — p cannot exceed port_to which was validated earlier.

hash_ipportip6_uadt() — net/netfilter/ipset/ip_set_hash_ipportip.c FP confidence=high

The function validates inputs carefully with multiple early-return checks. The flagged loop iterates over port numbers (u16 values, naturally bounded to 0-65535). Both 'port' (from ntohs, u16 range) and 'port_to' (from ip_set_get_h16, u16 range) are inherently bounded. The loop body only writes to a stack-allocated struct field and calls a function pointer — no array indexing or pointer arithmetic using the port value. There is no OOB memory access possible from this loop, only at most 65536 iterations.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 346
Taint snippetport = ntohs(h->next.port);
Tainted varport
Loopfor_loop line 347
Sink snippetfor (; port <= port_to; port++) {
Possibly guardedno
Dismissed: The scanner flagged 'port' from ntohs(h->next.port) as controlling loop iteration count. However, ntohs() always returns a value in [0, 65535], and port_to is similarly bounded by ip_set_get_h16() to [0, 65535]. The loop can run at most 65536 times. More critically, the loop body does not index into any buffer using 'port' — it assigns to e.port (a stack field) and calls adtfn. No counterexample can be constructed where this causes OOB memory access. The scanner is treating 'loop iteration count' as dangerous regardless of whether the loop body actually performs bounded-memory operations. This is a false positive.

hash_ipportnet4_uadt() — net/netfilter/ipset/ip_set_hash_ipportnet.c FP confidence=high

All three flagged loops iterate over IP/port ranges to insert hash entries — they do NOT index into a buffer using the tainted values as offsets. The loop variables (ip, p, ip2) are used as values stored in the hash element 'e', not as array indices or pointer offsets. The IPSET_MAX_RANGE guard at line 286 limits total computational iterations across all three nested loops. The taint sources (h->next.ip, h->next.port, h->next.ip2) are kernel-internal resume-state values saved by hash_ipportnet4_data_next() from a prior kernel execution, not raw server/network buffer data used for memory addressing. No buffer bounds issue exists.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 270
Taint snippetip = ntohl(h->next.ip);
Tainted varip
Loopfor_loop line 277
Sink snippetfor (; ip <= ip_to;) {
Possibly guardedno
Dismissed: h->next.ip is a kernel-internal resume cursor saved by hash_ipportnet4_data_next() in a prior invocation. The loop 'for (; ip <= ip_to;)' does not index a buffer — it calls adtfn() with an htonl(ip) value stored in element 'e'. The upper bound ip_to is separately validated. IPSET_MAX_RANGE (line 286) caps total work. No counterexample for OOB access can be constructed because no buffer is indexed by ip.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 249
Taint snippetport_to = port = ntohs(e.port);
Tainted varp
Loopfor_loop line 279
Sink snippetfor (; p <= port_to; p++) {
Possibly guardedno
Dismissed: h->next.port is a kernel-internal resume cursor. The port loop 'for (; p <= port_to; p++)' stores p as htons(p) in e.port and calls adtfn() — no buffer indexing. port_to is bounded by u16 range (0-65535). IPSET_MAX_RANGE caps total iterations. No OOB counterexample possible.

Finding #3 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 272
Taint snippetip2 = ntohl(h->next.ip2);
Tainted varip2
Loopdo_loop line 281
Sink snippetdo {
Possibly guardedno
Dismissed: h->next.ip2 is a kernel-internal resume cursor. The do-while loop uses ip2 as a value stored in e.ip2 via htonl(ip2) — no buffer indexing. The loop condition 'ip2++ < ip2_to' and the IPSET_MAX_RANGE guard (line 286) bound execution. The check at line 263 'if (ip2_from + UINT_MAX == ip2_to)' prevents a full 32-bit wraparound range. No OOB counterexample possible.

hash_ipportnet6_uadt() — net/netfilter/ipset/ip_set_hash_ipportnet.c FP confidence=high

The function validates protocol attributes and CIDR ranges carefully. The flagged loop iterates port numbers (u16 range, max 65535) from 'port' to 'port_to', both of which are bounded by 16-bit arithmetic. No buffer is indexed by the port value inside the loop — adtfn() is called with a struct element containing the port number. There is no OOB memory access possible regardless of the port value.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 504
Taint snippetport = ntohs(h->next.port);
Tainted varport
Loopfor_loop line 505
Sink snippetfor (; port <= port_to; port++) {
Possibly guardedno
Dismissed: h->next.port is internal kernel ipset state (the resume point for retried operations), not directly server-supplied. Even treating it as tainted: both 'port' and 'port_to' are u16 values (ntohs/ip_set_get_h16 return 16-bit port numbers, max 65535). The loop body uses 'port' only as a port number value stored in e.port via htons(), not as an array index or allocation size. No buffer is accessed with 'port' as an offset. The maximum loop count is 65535 iterations, which is the normal ipset behavior for port ranges. No counterexample can be constructed that causes OOB memory access — the loop is a performance concern at most, not a memory safety issue.

hash_net4_uadt() — net/netfilter/ipset/ip_set_hash_net.c FP confidence=high

The function validates CIDR values, IP ranges, and critically has an explicit per-iteration counter (i > IPSET_MAX_RANGE) inside the loop that bounds total iterations regardless of the starting ip value. The tainted 'ip' from ntohl(h->next.ip) is internally computed kernel state from a previous invocation, not a raw network-supplied value, and does not index any buffer directly.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 193
Taint snippetip = ntohl(h->next.ip);
Tainted varip
Loopdo_loop line 194
Sink snippetdo {
Possibly guardedno
Dismissed: The loop contains an explicit iteration counter 'i' that triggers early exit via 'if (i > IPSET_MAX_RANGE) return -ERANGE' — this is a textbook per-iteration bounds check (form b). No counterexample exists: regardless of the value of 'ip' from ntohl(h->next.ip), the loop cannot execute more than IPSET_MAX_RANGE+1 times. Furthermore, 'ip' does not index any array or buffer; it is used only as an IP address value passed to htonl() and ip_set_range_to_cidr(). The h->next.ip value is set by the kernel itself in a prior invocation via hash_net4_data_next(), making it internally computed state rather than a direct server-supplied network buffer read.

hash_netiface4_uadt() — net/netfilter/ipset/ip_set_hash_netiface.c FP confidence=high

The function iterates over an IP address range, not a memory buffer. The tainted value 'ip' from ntohl(h->next.ip) is used as an IP address, not as an array index or memory offset. A per-iteration counter check (i > IPSET_MAX_RANGE) caps the number of loop iterations regardless of the ip value. No memory buffer is indexed by 'ip', so no OOB memory access is possible.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 261
Taint snippetip = ntohl(h->next.ip);
Tainted varip
Loopdo_loop line 262
Sink snippetdo {
Possibly guardedno
Dismissed: h->next.ip is kernel-maintained state set by hash_netiface4_data_next() during a prior (non-retried) invocation of this same function, where ip was already user-validated. More importantly, 'ip' is used as an IP address value (not a memory index), and the do-while loop has an explicit per-iteration guard 'if (i > IPSET_MAX_RANGE) return -ERANGE' that caps iterations regardless of the ip start value. No counterexample exists where ip causes OOB memory access: the loop body passes ip as a value to adtfn, not as an array offset. The scanner confused IP range iteration with buffer indexing.

hash_netnet4_uadt() — net/netfilter/ipset/ip_set_hash_netnet.c FP confidence=high

The loops in hash_netnet4_uadt iterate over IP address ranges, not array indices. The variables 'ip' and 'ip2' are u32 IP addresses used as loop counters compared against 'ip_to'/'ip2_to' bounds. No buffer is indexed by these values. The inner loop has a hard cap via 'i > IPSET_MAX_RANGE' that bounds total iterations regardless of starting IP values. Even if 'ip' and 'ip2' are loaded from h->next (which itself was written from prior iterations of the same loop), no OOB memory access is possible. The scanner incorrectly categorized IP-range iteration as unbounded buffer traversal.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 254
Taint snippetip = ntohl(h->next.ip[0]);
Tainted varip
Loopdo_loop line 260
Sink snippetdo {
Possibly guardedno
Dismissed: h->next.ip[0] is a kernel-internal value written by hash_netnet4_data_next() in a prior iteration of this same function. The value is an IP address used as a loop starting point, compared against ip_to (also user-supplied but bounded the same way). The loop does not index any memory buffer with 'ip'; it calls adtfn() per CIDR block. The IPSET_MAX_RANGE check at line 266 caps total iterations. No counterexample for OOB exists because no array indexing occurs.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 255
Taint snippetip2 = ntohl(h->next.ip[1]);
Tainted varip2
Loopdo_loop line 263
Sink snippetdo {
Possibly guardedno
Dismissed: h->next.ip[1] is similarly a kernel-internal value (set by hash_netnet4_data_next from e.ip[1]=htonl(ip2) in a prior call). Used as inner loop starting point against ip2_to. The IPSET_MAX_RANGE check at line 266 bounds total inner+outer iterations combined. No array buffer is indexed by ip2. No counterexample for OOB exists.

hash_netport4_uadt() — net/netfilter/ipset/ip_set_hash_netport.c FP confidence=high

The loops iterate over IP and port ranges to insert entries into a hash set via adtfn(). They do not perform indexed memory buffer access — no pointer arithmetic with tainted values against a received buffer. Both loops are protected by a per-iteration counter check 'if (i > IPSET_MAX_RANGE)' at line 251 which covers the combined iteration count across both loops, satisfying protection condition (b). Additionally, port values are inherently bounded to 16-bit (0–65535), and IP range wraparound is blocked by the 'ip + UINT_MAX == ip_to' check at line 233. The scanner is pattern-matching loop iteration counts as dangerous but the actual sink is a hash-set insertion function, not a memory buffer dereference.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 240
Taint snippetip = ntohl(h->next.ip);
Tainted varip
Loopdo_loop line 245
Sink snippetdo {
Possibly guardedno
Dismissed: The outer do-while loop iterates over IP addresses from 'ip' to 'ip_to'. The per-iteration check 'i > IPSET_MAX_RANGE' at line 251 accumulates across all inner and outer iterations and returns -ERANGE when exceeded. No buffer is indexed with 'ip' — it is stored into e.ip via htonl(ip). Counterexample attempt: even if ip=0 and ip_to=0xFFFFFFFF, the IPSET_MAX_RANGE check fires after at most IPSET_MAX_RANGE+1 total adtfn() calls. No OOB memory access is possible.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 221
Taint snippetport = port_to = ntohs(e.port);
Tainted varp
Loopfor_loop line 249
Sink snippetfor (; p <= port_to; p++, i++) {
Possibly guardedno
Dismissed: The inner for-loop iterates 'p' from port to port_to. Both values are derived from ntohs() of 16-bit network attributes, so they are inherently bounded to [0, 65535] — the maximum loop count from ports alone is 65536. Combined with the 'i > IPSET_MAX_RANGE' per-iteration check, the total iterations are strictly bounded. The value 'p' is only used as htons(p) stored into e.port — no buffer indexing occurs. No counterexample exists that causes OOB access.

hash_netport6_uadt() — net/netfilter/ipset/ip_set_hash_netport.c FP confidence=high

The function validates CIDR, protocol, and port attributes from netlink. The flagged loop iterates over a range of port numbers (u16 values, 0-65535), calling adtfn() for each port. This is not a buffer traversal — 'port' is used as a port number value passed to adtfn(), not as a memory index or allocation size. The loop is bounded by u16 semantics (max 65536 iterations) and cannot cause OOB memory access.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 447
Taint snippetport = ntohs(h->next.port);
Tainted varport
Loopfor_loop line 448
Sink snippetfor (; port <= port_to; port++) {
Possibly guardedno
Dismissed: The scanner misidentifies this as a buffer bounds problem. 'port' is a u16 port number (0-65535) used as a value argument to adtfn(), not as a buffer index. The loop iterates over a range of port numbers, with both 'port' and 'port_to' naturally bounded to [0, 65535] by their u16 origins (ntohs() of __be16 and ip_set_get_h16()). No counterexample exists: any values of port/port_to in [0,65535] will cause the loop to terminate in at most 65536 iterations without any OOB access. The retried path sets port=ntohs(h->next.port) which is also a u16 value. This is a false positive.

hash_netportnet4_uadt() — net/netfilter/ipset/ip_set_hash_netportnet.c FP confidence=high

The scanner misidentifies these loops as buffer-indexing loops. The loop variables (ip, ip2, p) are IP addresses and port numbers used to enumerate set members for hash operations — not buffer indices or allocation sizes. The loop termination is controlled by ip_to/ip2_to/port_to which are independently derived from validated netlink attributes. Additionally, the inner loop has an explicit IPSET_MAX_RANGE guard (line 318) that counts total iterations across all three loops and returns -ERANGE if exceeded, providing robust per-iteration protection. No OOB memory access is possible from these values.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 302
Taint snippetip = ntohl(h->next.ip[0]);
Tainted varip
Loopdo_loop line 310
Sink snippetdo {
Possibly guardedno
Dismissed: ip from h->next.ip[0] is a kernel-internal retry cursor (written by hash_netportnet4_data_next in a previous call), not a server-supplied value. It is used as a loop starting point, not an iteration count or buffer index. The outer do-while terminates when ip >= ip_to (validated from netlink attr). IPSET_MAX_RANGE bounds total iterations. No counterexample for OOB can be constructed because no buffer is indexed.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 281
Taint snippetport_to = port = ntohs(e.port);
Tainted varp
Loopfor_loop line 313
Sink snippetfor (; p <= port_to; p++) {
Possibly guardedno
Dismissed: p comes from ntohs(e.port) where e.port is a u16 port number from a validated netlink attribute (nla_get_be16). Port values are bounded to [0,65535] by the u16 type. The for loop p<=port_to where both are u32 with values ≤65535 is safe. IPSET_MAX_RANGE in the inner loop further limits total iterations. No buffer indexing occurs.

Finding #3 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 304
Taint snippetip2 = ntohl(h->next.ip[1]);
Tainted varip2
Loopdo_loop line 315
Sink snippetdo {
Possibly guardedno
Dismissed: ip2 from h->next.ip[1] is a kernel-internal retry cursor, not a server-supplied value. Used as loop starting point; inner do-while terminates when ip2 >= ip2_to (validated from netlink attr). The explicit IPSET_MAX_RANGE check at line 318 fires before any adtfn call when the total iteration count exceeds the limit, returning -ERANGE. No memory buffer is indexed by ip2.

hash_netportnet6_uadt() — net/netfilter/ipset/ip_set_hash_netportnet.c FP confidence=high

This function processes user/netlink-supplied attributes with proper validation of IP addresses, CIDRs, protocols, and port values. The flagged loop iterates over port numbers (not buffer indices), calling adtfn for each port in a range. The value h->next.port is kernel-internal state tracking retry position, not a server/network-supplied value. The loop has a natural upper bound (port <= port_to) and does not use port as a buffer index.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 561
Taint snippetport = ntohs(h->next.port);
Tainted varport
Loopfor_loop line 562
Sink snippetfor (; port <= port_to; port++) {
Possibly guardedno
Dismissed: h->next.port is kernel-internal state (resume point for retried operations), not a value received from a network packet or server response. The loop iterates over u16 port numbers (naturally bounded to 0-65535) using the condition 'port <= port_to', where port_to is itself bounded to 65535. No buffer is indexed by port; the only use of port in the loop body is htons(port) assigned to e.port. No counterexample can be constructed because: (1) the value is not server-supplied, (2) even if it were, if h->next.port > port_to, the loop body never executes, and (3) even if the loop runs many iterations, it only calls adtfn repeatedly with valid e.port values — no OOB memory access occurs.

do_ip_vs_get_ctl() — net/netfilter/ipvs/ip_vs_ctl.c FP confidence=high

The flagged copy_to_user() call uses strlen(buf)+1 as its size argument, where 'buf' is a kernel-local stack buffer of 64 bytes filled by sprintf() with a fixed format string. The content is entirely kernel-controlled (version constants and a table size value from kernel internals), not user-supplied or server-supplied. The taint source labeling is incorrect — the scanner appears to have flagged strlen() on a kernel-internal buffer as if it were user-controlled. The size is bounded by the format string and kernel constants, making it impossible for strlen(buf)+1 to exceed 64. All other cases (GET_SERVICES, GET_DESTS) properly validate the user-supplied *len against the computed struct_size() before use.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 3820
Taint snippetif (copy_to_user(user, buf, strlen(buf)+1) != 0) {
Tainted varstrlen(buf)+1
Unvalidated sizecopy_to_user() arg 2 line 3820 — size strlen(buf)+1
Sink snippetif (copy_to_user(user, buf, strlen(buf)+1) != 0) {
Possibly guardedno
Dismissed: The 'buf' variable is a 64-byte kernel stack buffer filled with sprintf() using a fixed format string containing only kernel-internal constants (IP_VS_VERSION_CODE and get_conn_tab_size()). strlen(buf)+1 is therefore bounded by the format output length, which is well under 64 bytes. No user-supplied data influences this size. The taint tracking appears to have been confused by the local strlen() call. No bounds check is needed here because the size is kernel-controlled. Counterexample: no concrete numeric values from user input can influence strlen(buf)+1 because the buffer content is entirely determined by kernel constants written by sprintf().

set_sctp_state() — net/netfilter/ipvs/ip_vs_proto_sctp.c FP confidence=high

The scanner incorrectly propagates taint from ntohs(sch->length) (used for chunk offset arithmetic) to sch->type (a separate u8 field in sctp_chunkhdr) and then through kernel-defined lookup tables. Key protections: (1) skb_header_pointer validates packet bounds and returns NULL if out of range; (2) the NULL check guards sch->type dereference; (3) chunk_type is a u8 field, not a 16-bit truncation; (4) chunk_type is bounds-checked before array use at line 415; (5) event and next_state come from kernel-defined constant tables, not raw server values; (6) sctp_state_name() has its own bounds check at line 369.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 405
Taint snippetint clen = ntohs(sch->length);
Tainted varsch
Pointer derefsch->type line 410
Sink snippetif (sch && sch->type == SCTP_CID_ABORT)
Possibly guardedno
Dismissed: skb_header_pointer() validates that cofs+ALIGN(clen,4) through cofs+ALIGN(clen,4)+sizeof(_sctpch) lies within the skb data; if not, it returns NULL. The explicit NULL check 'if (sch && sch->type == SCTP_CID_ABORT)' at line 410 guards the dereference. No counterexample is constructable: any offset that would go OOB causes skb_header_pointer to return NULL, which is checked.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 411
Taint snippetchunk_type = sch->type;
Tainted varchunk_type
Truncationline 411: 16 → 8-bit u8
Sink snippetchunk_type = sch->type;
Possibly guardedyes (heuristic)
Dismissed: struct sctp_chunkhdr has 'type' as __u8, not a 16-bit value. The scanner incorrectly associates the ntohs() taint from sch->length with sch->type, which is a completely separate 8-bit field. There is no 16-to-8-bit truncation here. False positive due to incorrect taint propagation.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 405
Taint snippetint clen = ntohs(sch->length);
Tainted varsch
Pointer derefsch->type line 411
Sink snippetchunk_type = sch->type;
Possibly guardedyes (heuristic)
Dismissed: Same reasoning as finding #1. sch at line 411 is guarded by the condition 'if (sch && sch->type == SCTP_CID_ABORT)' at line 410, so chunk_type = sch->type at line 411 is only reached when sch is non-NULL (i.e., skb_header_pointer validated the bounds). False positive.

Finding #4 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 405
Taint snippetint clen = ntohs(sch->length);
Tainted varchunk_type
Subscript[] line 416
Sink snippetsctp_events[chunk_type] : IP_VS_SCTP_DATA;
Possibly guardedno
Dismissed: chunk_type is a u8 (0-255). Line 415 explicitly checks 'chunk_type < sizeof(sctp_events)' before using it as an index. sizeof(sctp_events) returns the byte size of the array which equals the number of elements (each being one byte if u8, or larger if int — either way the check is 'chunk_type < number_of_elements'). No counterexample exists: any chunk_type >= sizeof(sctp_events) takes the else branch returning IP_VS_SCTP_DATA. False positive.

Finding #5 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 405
Taint snippetint clen = ntohs(sch->length);
Tainted varevent
Subscript[] line 428
Sink snippetnext_state = sctp_states[direction][event][cp->state];
Possibly guardedno
Dismissed: event is the result of a lookup in the kernel-defined sctp_events[] table (or IP_VS_SCTP_DATA constant). These are kernel-internal constants, not server-supplied values. The taint chain through ntohs()->chunk_type->sctp_events[chunk_type] ends at a kernel constant. The sctp_states table dimensions match the defined event constants by construction. False positive.

Finding #6 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 405
Taint snippetint clen = ntohs(sch->length);
Tainted varnext_state
Subscript[] line 462
Sink snippetcp->timeout = pd->timeout_table[cp->state = next_state];
Possibly guardedno
Dismissed: next_state is derived from sctp_states[direction][event][cp->state], a kernel-defined 3D constant table. Its values are IP_VS_SCTP_S_* enum constants guaranteed to be within the timeout_table bounds by kernel construction. Not a server-supplied value in any meaningful sense. False positive.

Finding #7 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 405
Taint snippetint clen = ntohs(sch->length);
Tainted varnext_state
Subscript[] line 464
Sink snippetcp->timeout = sctp_timeouts[cp->state = next_state];
Possibly guardedno
Dismissed: Same as finding #6. next_state from kernel constant table used to index sctp_timeouts[], another kernel-defined array sized to IP_VS_SCTP_S_LAST. False positive.

Finding #8 — Category C — cross-function via sctp_state_name() — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 405
Taint snippetint clen = ntohs(sch->length);
Tainted varnext_state
Call siteline 443 — passes next_state to sctp_state_name()
Call snippetsctp_state_name(next_state),
Subscript (in callee)[] line 371
Sink snippetif (sctp_state_name_table[state])
Possibly guardedyes (heuristic)
Dismissed: next_state is a kernel table constant (not server-supplied). Additionally, sctp_state_name() itself guards with 'if (state >= IP_VS_SCTP_S_LAST) return ERR!' before any array access (line 369-370). Both the value origin (kernel constant) and the callee's own validation make this a false positive.

Finding #9 — Category C — cross-function via sctp_state_name() — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 405
Taint snippetint clen = ntohs(sch->length);
Tainted varnext_state
Call siteline 443 — passes next_state to sctp_state_name()
Call snippetsctp_state_name(next_state),
Subscript (in callee)[] line 372
Sink snippetreturn sctp_state_name_table[state];
Possibly guardedyes (heuristic)
Dismissed: Same as finding #8. sctp_state_name() validates state >= IP_VS_SCTP_S_LAST before accessing sctp_state_name_table[state] at line 372. The guard at line 369 covers both array accesses at lines 371 and 372. False positive.

ip_vs_proc_sync_conn() — net/netfilter/ipvs/ip_vs_sync.c FP confidence=high

ip_vs_proc_sync_conn() applies careful input validation on the server-supplied state value before passing it to ip_vs_proc_conn(). For non-template connections, state is validated against pp->num_states and the function returns early on failure. For template connections, the array subscript sink in ip_vs_proc_conn() is guarded by !(flags & IP_VS_CONN_F_TEMPLATE), so the template path takes the else branch (fixed timeout) and never indexes into timeout_table. The two guards together make OOB access impossible.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 1149
Taint snippetstate = ntohs(s->v4.state);
Tainted varstate
Call siteline 1177 — passes state to ip_vs_proc_conn()
Call snippetip_vs_proc_conn(ipvs, &param, flags, state, s->v4.protocol, af,
Subscript (in callee)[] line 948
Sink snippetcp->timeout = pd->timeout_table[state];
Possibly guardedyes (heuristic)
Dismissed: Two complementary guards prevent OOB: (1) for non-template connections, ip_vs_proc_sync_conn() checks state >= pp->num_states and returns retc=40 before calling ip_vs_proc_conn(); (2) the sink in ip_vs_proc_conn() at line 948 is inside 'if (!(flags & IP_VS_CONN_F_TEMPLATE) && pd && pd->timeout_table)', so template connections never reach the array indexing. No counterexample could be constructed — every path with an unchecked state value skips the array subscript sink. False positive.

ip_vs_process_message() — net/netfilter/ipvs/ip_vs_sync.c FP confidence=high

ip_vs_process_message() has a layered validation discipline: it checks that msg_end (= p + size) does not exceed buffer+buflen (line 1245) before passing it to ip_vs_proc_sync_conn(). The callee itself further validates all pointer arithmetic against msg_end before any dereference (lines 1098, 1106, 1111). No counterexample can be constructed that passes the caller's guard yet causes OOB in the callee.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1242
Taint snippetsize = ntohs(s->v4.ver_size) & SVER_MASK;
Tainted varmsg_end
Call siteline 1255 — passes msg_end to ip_vs_proc_sync_conn()
Call snippetretc = ip_vs_proc_sync_conn(ipvs, p, msg_end);
Loopwhile_loop line 1102
Sink snippetwhile (p < msg_end) {
Possibly guardedyes (heuristic)
Dismissed: Line 1245 ensures msg_end <= buffer+buflen before the call. Inside ip_vs_proc_sync_conn(), msg_end is used only as a loop/comparison bound with callee-internal sub-checks (p>msg_end at line 1098, p+2>msg_end at line 1106, p+plen>msg_end at line 1111). No counterexample exists: any size value that passes the caller's guard produces a msg_end within the buffer, and callee guards catch undersized structs. The finding is a false positive.

ip_vs_process_message_v0() — net/netfilter/ipvs/ip_vs_sync.c FP confidence=high

ip_vs_process_message_v0() validates state against pp->num_states for non-template connections and skips (continue) any connection with out-of-range state before calling ip_vs_proc_conn(). The sink in ip_vs_proc_conn() at line 948 is further guarded by !(flags & IP_VS_CONN_F_TEMPLATE), which matches the same condition under which the caller validated state. No counterexample can be constructed that passes the caller's guard yet causes OOB at the sink.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 992
Taint snippetstate = ntohs(s->state);
Tainted varstate
Call siteline 1018 — passes state to ip_vs_proc_conn()
Call snippetip_vs_proc_conn(ipvs, &param, flags, state, s->protocol, AF_INET,
Subscript (in callee)[] line 948
Sink snippetcp->timeout = pd->timeout_table[state];
Possibly guardedyes (heuristic)
Dismissed: For non-template connections, the caller checks state >= pp->num_states and continues (skipping ip_vs_proc_conn()) if out of range. The sink pd->timeout_table[state] in ip_vs_proc_conn() is guarded by !(flags & IP_VS_CONN_F_TEMPLATE), exactly the condition under which the caller already validated state < pp->num_states. No counterexample exists: any state value that would reach line 948 has already been bounds-checked. False positive.

conntrack_pptp_help() — net/netfilter/nf_conntrack_pptp.c FP confidence=high

The function carefully validates network-supplied values before use. The flagged array access at line 498 is protected by explicit bounds checks (msg > 0 && msg <= PPTP_MSG_MAX) in the same conditional expression, using C short-circuit evaluation semantics. The static scanner failed to recognize these guards as sufficient because they appear in the same expression as the subscript rather than in a preceding statement.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 497
Taint snippetmsg = ntohs(ctlh->messageType);
Tainted varmsg
Subscript[] line 498
Sink snippetif (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg])
Possibly guardedno
Dismissed: The expression 'if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg])' uses C short-circuit evaluation: pptp_msg_size[msg] is only evaluated when both msg > 0 and msg <= PPTP_MSG_MAX are true, constraining msg to [1, PPTP_MSG_MAX]. No counterexample can be constructed — any msg value that reaches the array access is already bounded within the valid array index range. The scanner incorrectly reported 'possibly guarded: no', when in fact the guards are in the same conditional expression and are effective.

hash_by_src() — net/netfilter/nf_nat_core.c FP confidence=high

The function implements NAT port selection. The 'range' parameter comes from kernel NAT rule configuration (iptables/nftables rules set by the administrator), not directly from network packet data. Even treating the values as tainted, the loop controlled by 'attempts' does not index into any buffer - it iterates over port number candidates calling nf_nat_used_tuple_harder(). The attempts variable is also hard-capped at NF_NAT_MAX_ATTEMPTS before the loop. No OOB memory access is possible from this flow.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 643
Taint snippetmax = ntohs(range->max_proto.all);
Tainted varattempts
Loopfor_loop line 669
Sink snippetfor (i = 0; i < attempts; i++, off++) {
Possibly guardedno
Dismissed: The 'range' struct comes from NAT rule configuration (administrator-controlled), not from network packets. The loop body computes 'min + off % range_size' for port selection — no buffer is indexed by 'attempts' or 'i'. The 'attempts' variable is explicitly capped at NF_NAT_MAX_ATTEMPTS (lines 659-660) before the loop. No counterexample for OOB access can be constructed because there is no buffer being traversed — only port number arithmetic and a lookup call. False positive.

nf_tables_delchain() — net/netfilter/nf_tables_api.c FP confidence=high

The scanner has made a fundamental attribution error. The taint source is reported as be64_to_cpu() at line 3314 (reading a handle from a netlink attribute), but the flagged sink at line 3351 is 'use = chain->use' — this reads chain->use, which is an internal kernel reference counter maintained by the netlink/nftables subsystem, not derived from the be64_to_cpu() result. The handle was used only to look up the chain object via nft_chain_lookup_byhandle(); after that lookup, the chain pointer is an internal kernel object whose 'use' field is managed by the kernel. The taint propagation from be64_to_cpu() through the chain lookup to chain->use is a false positive — the scanner has followed the pointer through the lookup function and incorrectly attributed the internal reference count as tainted by user input. Additionally, chain->use is a u32 field in struct nft_chain, not a 64-bit value, so there is no truncation occurring.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcebe64_to_cpu() line 3351
Taint snippetuse = chain->use;
Tainted varuse
Truncationline 3351: 64 → 32-bit u32
Sink snippetuse = chain->use;
Possibly guardedyes (heuristic)
Dismissed: The taint path is incorrect. be64_to_cpu() at line 3314 converts a user-supplied chain handle (a u64 lookup key). This handle is passed to nft_chain_lookup_byhandle(), which searches the kernel's internal chain list and returns a pointer to a kernel-managed struct nft_chain. The assignment 'use = chain->use' at line 3351 reads the kernel-internal reference counter field (u32) from this struct — it is not influenced by the user-supplied handle value beyond selecting which chain to look at. No truncation of a 64-bit user value occurs. The check at line 3347-3349 (chain->use > 0) and the subsequent decrement loop provide correct internal logic. This is a false positive caused by overly aggressive taint propagation through a pointer-lookup function.

nf_tables_newchain() — net/netfilter/nf_tables_api.c FP confidence=high

Both findings are false positives. Finding #1: the policy value from ntohl() is explicitly validated in a switch statement that only accepts NF_DROP and NF_ACCEPT before being assigned to the u8 variable — any other 32-bit value returns -EINVAL, so no truncation surprise is possible. Finding #2: the taint chain is misattributed — chain->flags is a kernel-internal field of type u8 (defined in struct nft_chain), not derived from be64_to_cpu(). The be64_to_cpu() call produces the 'handle' used in nft_chain_lookup_byhandle(), not chain->flags. The scanner incorrectly propagated taint from handle through the chain pointer to chain->flags.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 3169
Taint snippetpolicy = ntohl(nla_get_be32(nla[NFTA_CHAIN_POLICY]));
Tainted varpolicy
Truncationline 3169: 32 → 8-bit u8
Sink snippetpolicy = ntohl(nla_get_be32(nla[NFTA_CHAIN_POLICY]));
Possibly guardedno
Dismissed: The 32-bit value from ntohl() is validated via a switch statement at lines 3170-3176 that only permits NF_DROP (1) and NF_ACCEPT (0), returning -EINVAL for any other value. No counterexample exists: any 32-bit value that is not 0 or 1 is rejected before assignment, so the truncation to u8 is safe. The switch check comes BEFORE the assignment completes its effect is used, and the only values that survive are within u8 range.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcebe64_to_cpu() line 3182
Taint snippetflags = chain->flags;
Tainted varflags
Truncationline 3182: 64 → 32-bit u32
Sink snippetflags = chain->flags;
Possibly guardedyes (heuristic)
Dismissed: The scanner incorrectly traces taint from be64_to_cpu() (line 3136, producing 'handle') through the nft_chain_lookup_byhandle() call to 'chain', and then to chain->flags at line 3182. However, chain->flags is a kernel-internal struct field populated by the kernel itself when the chain was created — it is not derived from the network-supplied handle value. The handle is merely a lookup key; the returned chain pointer points to a kernel object whose flags field is set by nft_chain_init() or similar kernel code. This is a classic false positive: taint laundered through a pointer dereference into a kernel-owned structure. Additionally, chain->flags is typed as u8 in struct nft_chain, so even if it were tainted, assigning a u8 to a u32 is a widening (zero-extension), not a truncation.

nf_tables_newobj() — net/netfilter/nf_tables_api.c FP confidence=high

The scanner propagates taint from `objtype` (user-supplied) through `nft_obj_type_get()` into `type`, but `nft_obj_type_get()` is a kernel registry lookup — it either returns ERR_PTR (checked at line 8359) or a pointer to a statically-registered kernel-internal `nft_object_type` struct. The fields `type->maxattr`, `type->policy`, `type->ops`, and `ops->size` are kernel constants defined at module registration time, not user-controlled values. The IS_ERR() guard at line 8359 is both necessary and sufficient to ensure `type` is a valid kernel pointer before use.

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 8322
Taint snippetobjtype = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
Tainted vartype
Call siteline 8364 — passes type to nft_obj_init()
Call snippetobj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
Sink (in callee)memset() line 8172 (arg 2, role=size_mul_overflow)
Sink snippetmemset(tb, 0, sizeof(tb[0]) * (type->maxattr + 1));
Possibly guardedno
Dismissed: type->maxattr is a field of a kernel-registered nft_object_type struct, not user data. nft_obj_type_get() acts as a validation gate returning a trusted kernel pointer or ERR_PTR. The IS_ERR check at line 8359 guards all subsequent uses. The memset size (type->maxattr+1) is entirely kernel-controlled. No counterexample possible — user cannot influence the value of maxattr in a registered type.

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 8322
Taint snippetobjtype = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
Tainted vartype
Call siteline 8364 — passes type to nft_obj_init()
Call snippetobj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
Sink (in callee)kzalloc() line 8186 (arg 0, role=size_mul_overflow)
Sink snippetobj = kzalloc(sizeof(*obj) + ops->size, GFP_KERNEL_ACCOUNT);
Possibly guardedno
Dismissed: ops->size is a field of a kernel-registered nft_object_ops struct (reachable via type->ops or type->select_ops). User cannot influence this value. The kzalloc size (sizeof(*obj) + ops->size) uses only kernel-defined constants. No counterexample possible.

Finding #3 — Category E — cross-function via nft_obj_init() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 8322
Taint snippetobjtype = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
Tainted vartype
Call siteline 8364 — passes type to nft_obj_init()
Call snippetobj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
Pointer dereftype-> line 8194
Sink snippetobj->ops = ops;
Possibly guardedno
Dismissed: obj->ops = ops is an assignment to a freshly kzalloc'd object (checked at line 8187). obj is a valid kernel allocation at this point. ops is derived from kernel-registered type struct, not user data. This is normal initialization, not a vulnerable dereference.

nf_tables_newrule() — net/netfilter/nf_tables_api.c FP confidence=high

All findings are false positives caused by the scanner incorrectly propagating taint from `handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]))` through `__nft_rule_lookup()` to a completely separate `rule` pointer that is freshly allocated by `kzalloc()` at line 4438. The newly allocated `rule` is a kernel-local buffer with no relationship to the server-supplied handle value. Similarly, `size` is bounded by the `if (size >= 1 << 12)` guard, and `ulen` is bounded by netlink attribute size constraints. The integer truncation findings (#7-9) are also false positives because all the return values are native `int` types.

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

CategoryCat B — integer overflow: sizeof(*rule) + size + usize
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varrule
Overflow exprsizeof(*rule) + size + usize
Safe fixkmalloc_array() or check_mul_overflow()
Sinkkzalloc() line 4438 (arg 0, role=size_mul_overflow)
Sink snippetrule = kzalloc(sizeof(*rule) + size + usize, GFP_KERNEL_ACCOUNT);
Possibly guardedno
Dismissed: The scanner incorrectly traces taint from `handle` (a u64 handle) into `rule` via `__nft_rule_lookup`, then into the kzalloc size expression. In reality, `size` is bounded by `if (size >= 1 << 12) goto err_release_expr` (< 4096 bytes), and `usize` is bounded by netlink attribute limits. `sizeof(*rule)` is a compile-time constant. No overflow is possible. The allocation `sizeof(*rule) + size + usize` is safe: max is ~(sizeof(nft_rule) + 4095 + sizeof(nft_userdata) + 65535) which fits in size_t with no wraparound.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varrule
Pointer derefrule->handle line 4444
Sink snippetrule->handle = handle;
Possibly guardedyes (heuristic)
Dismissed: The `rule` at line 4444 is a freshly kernel-allocated struct via `kzalloc()` at line 4438, not a pointer derived from a server-supplied offset. The scanner incorrectly propagates taint from the handle lookup. Writing `rule->handle = handle` is writing into a locally-allocated buffer - entirely safe.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varrule
Pointer derefrule->dlen line 4445
Sink snippetrule->dlen = size;
Possibly guardedyes (heuristic)
Dismissed: Same as finding #2. `rule` is kernel-allocated. `rule->dlen = size` writes a locally-computed bounded value into a local struct. False positive.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varrule
Pointer derefrule->udata line 4446
Sink snippetrule->udata = ulen ? 1 : 0;
Possibly guardedyes (heuristic)
Dismissed: Same as finding #2. `rule->udata = ulen ? 1 : 0` writes a boolean into a kernel-allocated struct. False positive.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varudata
Pointer derefudata->len line 4450
Sink snippetudata->len = ulen - 1;
Possibly guardedno
Dismissed: `udata = nft_userdata(rule)` derives `udata` from the kernel-allocated `rule` pointer, which was sized to include `usize = sizeof(struct nft_userdata) + ulen`. So `udata->len` access is within the allocated buffer. The taint chain from `be64_to_cpu` to `udata` is a scanner artifact. False positive.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varudata
Pointer derefudata->data line 4451
Sink snippetnla_memcpy(udata->data, nla[NFTA_RULE_USERDATA], ulen);
Possibly guardedno
Dismissed: Same as finding #5. `udata->data` is within the kernel-allocated buffer sized to hold it. `nla_memcpy` copies exactly `ulen` bytes which is the size allocated. False positive.

Finding #7 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcebe64_to_cpu() line 4456
Taint snippeterr = nf_tables_newexpr(&ctx, &expr_info[i], expr);
Tainted varerr
Truncationline 4456: 64 → 32-bit u32
Sink snippeterr = nf_tables_newexpr(&ctx, &expr_info[i], expr);
Possibly guardedno
Dismissed: `nf_tables_newexpr()` returns `int` (32-bit), and `err` is declared as `int`. There is no 64-bit to 32-bit truncation. The scanner incorrectly believes this is a wide-to-narrow truncation because it propagated taint from the 64-bit `handle` variable through multiple function calls. False positive.

Finding #8 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcebe64_to_cpu() line 4472
Taint snippeterr = PTR_ERR(flow);
Tainted varerr
Truncationline 4472: 64 → 32-bit u32
Sink snippeterr = PTR_ERR(flow);
Possibly guardedno
Dismissed: `PTR_ERR(flow)` returns `long` which is assigned to `int err`. On 64-bit systems, PTR_ERR values are small negative errno values that fit in int. This is a standard kernel pattern. Even if technically a narrowing, it's safe because error pointers encode small errno values. The taint propagation from `be64_to_cpu` to `flow` to `err` is incorrect. False positive.

Finding #9 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcebe64_to_cpu() line 4488
Taint snippeterr = nft_delrule(&ctx, old_rule);
Tainted varerr
Truncationline 4488: 64 → 32-bit u32
Sink snippeterr = nft_delrule(&ctx, old_rule);
Possibly guardedno
Dismissed: `nft_delrule()` returns `int`. `err` is `int`. No truncation occurs. The scanner's taint propagation from `be64_to_cpu(handle)` through `old_rule` to `nft_delrule` to `err` is a false chain. False positive.

Finding #10 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varrule
Pointer derefrule->list line 4497
Sink snippetlist_add_tail_rcu(&rule->list, &old_rule->list);
Possibly guardedyes (heuristic)
Dismissed: `rule` at line 4497 is the freshly kernel-allocated struct. `list_add_tail_rcu(&rule->list, ...)` accesses the kernel-allocated buffer. False positive from incorrect taint propagation.

Finding #11 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varrule
Pointer derefrule->list line 4507
Sink snippetlist_add_rcu(&rule->list, &old_rule->list);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #10. `rule->list` at line 4507 is within the kernel-allocated buffer. False positive.

Finding #12 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varrule
Pointer derefrule->list line 4509
Sink snippetlist_add_tail_rcu(&rule->list, &chain->rules);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #10. `rule->list` at line 4509 is within the kernel-allocated buffer. False positive.

Finding #13 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varrule
Pointer derefrule->list line 4512
Sink snippetlist_add_tail_rcu(&rule->list, &old_rule->list);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #10. `rule->list` at line 4512 is within the kernel-allocated buffer. False positive.

Finding #14 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe64_to_cpu() line 4364
Taint snippethandle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
Tainted varrule
Pointer derefrule->list line 4514
Sink snippetlist_add_rcu(&rule->list, &chain->rules);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #10. `rule->list` at line 4514 is within the kernel-allocated buffer. False positive.

nf_tables_newset() — net/netfilter/nf_tables_api.c FP confidence=high

All 20 findings are false positives. The taint source is `flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]))` from a user-space netlink message (not a network server response), and `flags` is properly bounds-checked at lines 5474-5491 with a whitelist mask check and several invalid combination checks. The `set` pointer is NOT derived from `flags` via offset arithmetic — it is allocated by `kvzalloc(alloc_size, GFP_KERNEL_ACCOUNT)` at line 5655 and is a locally-allocated kernel struct. The scanner has incorrectly propagated taint from `flags` to `alloc_size` (via `size = ops->privsize(nla, &desc)` and `udlen = nla_len(...)`) and then to `set`. However: (1) `alloc_size` is independently guarded at line 5649 (`alloc_size < size || alloc_size > INT_MAX`); (2) `set` is allocated with `alloc_size` bytes and is a kernel-managed heap object; (3) all field accesses on `set` are writes to a freshly allocated, correctly-sized buffer — not reads from a received packet. The Category E findings (#2-#20) are especially clearly false positives because `set` is not a pointer derived from a server-supplied offset — it is a pointer returned by `kvzalloc`. The taint propagation from `flags` to `set` in the scanner is spurious. | The scanner incorrectly propagated taint from the user-supplied 'flags' value (ntohl at line 5473) through alloc_size computation to the 'set' pointer returned by kvzalloc(). The 'set' pointer is a fresh kernel heap allocation (kvzalloc at line 5655), not a pointer derived from server-supplied offset arithmetic. All struct field accesses on 'set' are accesses into a locally-allocated nft_set struct. The taint chain flags->size->alloc_size->set is not a security-relevant taint propagation: kvzalloc() takes a size argument but always returns a fresh allocation at a kernel-controlled address. Additionally, set->num_exprs is written locally (line 5709) from a locally-maintained counter, not from user input.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varalloc_size
Sinkkvzalloc() line 5655 (arg 0, role=size)
Sink snippetset = kvzalloc(alloc_size, GFP_KERNEL_ACCOUNT);
Possibly guardedyes (heuristic)
Dismissed: flags is user-supplied (netlink, not a server response). It is checked against a strict whitelist mask at line 5474 and several mutually-exclusive combination checks follow. alloc_size is computed as sizeof(*set) + size + udlen; size comes from ops->privsize() (a kernel function) and udlen from nla_len() (bounded by netlink attribute length). The overflow guard at line 5649 (alloc_size < size || alloc_size > INT_MAX) ensures no integer overflow or undersized allocation. No counterexample exists that passes all guards yet causes harm.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->data line 5674
Sink snippetudata = set->data + size;
Possibly guardedyes (heuristic)
Dismissed: set is not derived from a server-supplied offset. It is a pointer returned by kvzalloc(alloc_size) at line 5655 — a locally-allocated kernel struct of exactly alloc_size bytes. set->data is the flexible member/trailing data region within that allocation, accessed at offset size which was included in alloc_size. The scanner incorrectly propagated taint from flags to set.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->bindings line 5678
Sink snippetINIT_LIST_HEAD(&set->bindings);
Possibly guardedyes (heuristic)
Dismissed: set is a locally kernel-allocated struct via kvzalloc. set->bindings is a field within that allocation — a simple write to a locally-created object. Spurious taint propagation from flags.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->catchall_list line 5679
Sink snippetINIT_LIST_HEAD(&set->catchall_list);
Possibly guardedyes (heuristic)
Dismissed: Same as #3 — set is a locally-allocated kernel struct. INIT_LIST_HEAD on set->catchall_list is a safe write within the allocated buffer.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->refs line 5680
Sink snippetrefcount_set(&set->refs, 1);
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. refcount_set on set->refs is a safe field write.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->table line 5681
Sink snippetset->table = table;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->table write is safe.

Finding #7 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->net line 5682
Sink snippetwrite_pnet(&set->net, net);
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. write_pnet on set->net is safe.

Finding #8 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->ops line 5683
Sink snippetset->ops = ops;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->ops write is safe.

Finding #9 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->ktype line 5684
Sink snippetset->ktype = desc.ktype;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->ktype write is safe.

Finding #10 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->klen line 5685
Sink snippetset->klen = desc.klen;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->klen write is safe.

Finding #11 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->dtype line 5686
Sink snippetset->dtype = desc.dtype;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->dtype write is safe.

Finding #12 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->objtype line 5687
Sink snippetset->objtype = desc.objtype;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->objtype write is safe.

Finding #13 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->dlen line 5688
Sink snippetset->dlen = desc.dlen;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->dlen write is safe.

Finding #14 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->flags line 5689
Sink snippetset->flags = flags;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->flags write is safe. flags itself was validated by the whitelist mask check at line 5474.

Finding #15 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->size line 5690
Sink snippetset->size = desc.size;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->size write is safe.

Finding #16 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->policy line 5691
Sink snippetset->policy = desc.policy;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->policy write is safe.

Finding #17 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->udlen line 5692
Sink snippetset->udlen = udlen;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->udlen write is safe. udlen itself is bounded by nla_len() which is bounded by the netlink message size.

Finding #18 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->udata line 5693
Sink snippetset->udata = udata;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->udata write is safe; udata points into the trailing region of the allocation.

Finding #19 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->timeout line 5694
Sink snippetset->timeout = desc.timeout;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->timeout write is safe.

Finding #20 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->gc_int line 5695
Sink snippetset->gc_int = desc.gc_int;
Possibly guardedyes (heuristic)
Dismissed: set is locally allocated. set->gc_int write is safe.

Finding #21 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->field_count line 5697
Sink snippetset->field_count = desc.field_count;
Possibly guardedyes (heuristic)
Dismissed: set is allocated by kvzalloc() at line 5655; it is a kernel-local allocation, not a pointer derived from server-supplied offset arithmetic. The taint propagation flags->set->set->field_count is a scanner artifact.

Finding #22 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->field_len line 5699
Sink snippetset->field_len[i] = desc.field_len[i];
Possibly guardedyes (heuristic)
Dismissed: set->field_len[] is an array within the kernel-allocated nft_set struct. desc.field_count is bounded by NFT_REG32_COUNT in practice. set is a local kernel allocation.

Finding #23 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->exprs line 5705
Sink snippeterr = nft_set_expr_alloc(&ctx, set, nla, set->exprs, &num_exprs, flags);
Possibly guardedyes (heuristic)
Dismissed: set->exprs is a field of the locally-allocated nft_set struct. The scanner incorrectly traces taint from flags to set.

Finding #24 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->num_exprs line 5709
Sink snippetset->num_exprs = num_exprs;
Possibly guardedyes (heuristic)
Dismissed: set->num_exprs is written with a locally-maintained counter num_exprs returned from nft_set_expr_alloc(). The set pointer is a local kernel allocation.

Finding #25 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->handle line 5710
Sink snippetset->handle = nf_tables_alloc_handle(table);
Possibly guardedyes (heuristic)
Dismissed: set->handle is assigned from nf_tables_alloc_handle(table) which increments a local counter. set is a kernel allocation.

Finding #26 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->pending_update line 5711
Sink snippetINIT_LIST_HEAD(&set->pending_update);
Possibly guardedyes (heuristic)
Dismissed: INIT_LIST_HEAD on a field of a locally-allocated struct. No server-supplied offset involved.

Finding #27 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->list line 5717
Sink snippetlist_add_tail_rcu(&set->list, &table->sets);
Possibly guardedyes (heuristic)
Dismissed: list_add_tail_rcu on a field of a locally-allocated struct. The set pointer is not derived from any server offset.

Finding #28 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Loopfor_loop line 5722
Sink snippetfor (i = 0; i < set->num_exprs; i++)
Possibly guardedyes (heuristic)
Dismissed: set->num_exprs was set at line 5709 to num_exprs, a locally-maintained counter from nft_set_expr_alloc(). The error-path loop at line 5722 iterates exactly over the expressions that were successfully allocated. No OOB possible.

Finding #29 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->num_exprs line 5722
Sink snippetfor (i = 0; i < set->num_exprs; i++)
Possibly guardedyes (heuristic)
Dismissed: set->num_exprs is a field of a locally-allocated struct written with a locally-maintained counter. False positive.

Finding #30 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->exprs line 5723
Sink snippetnft_expr_destroy(&ctx, set->exprs[i]);
Possibly guardedyes (heuristic)
Dismissed: set->exprs is a field of the locally-allocated nft_set struct. The error-path loop is bounded by num_exprs which was locally counted.

Finding #31 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 5473
Taint snippetflags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Tainted varset
Pointer derefset->name line 5727
Sink snippetkfree(set->name);
Possibly guardedyes (heuristic)
Dismissed: set->name is a field of the locally-allocated nft_set struct. kfree on a kernel-controlled pointer in the error path. No server-supplied offset involved.
The function validates class_max with both a lower bound (> 0) and upper bound (<= NF_CT_MAX_EXPECT_CLASSES) check before the loop. Both array accesses in the loop (tb[] and helper->expect_policy[]) are bounded by NF_CT_MAX_EXPECT_CLASSES, which is the enforced maximum. No counterexample can be constructed that passes the guard yet causes OOB.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 199
Taint snippetclass_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
Tainted varclass_max
Loopfor_loop line 205
Sink snippetfor (i = 0; i < class_max; i++) {
Possibly guardedyes (heuristic)
Dismissed: class_max is validated: zero check (line 200-201) and upper-bound check against NF_CT_MAX_EXPECT_CLASSES (line 202-203). The loop index i < class_max <= NF_CT_MAX_EXPECT_CLASSES, so helper->expect_policy[i] stays within the array bounds. The tb[] access with NFCTH_POLICY_SET+i is safe because NFCTH_POLICY_SET_MAX is defined to accommodate all NF_CT_MAX_EXPECT_CLASSES policy slots. No counterexample could be constructed that bypasses these guards.
nfnl_hook_entries_head() validates the tainted 'hook' parameter against ARRAY_SIZE() for each array before accessing it. Every flagged array subscript is immediately preceded by a bounds check that returns ERR_PTR on failure. The function is effectively the validator for the hook number. The caller also has a preliminary sanity check (hooknum > 255), but the per-array ARRAY_SIZE guards in the callee are the definitive protection.

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

CategoryCat C — server value → array subscript
Taint sourcentohl() line 392
Taint snippethooknum = ntohl(nla_get_be32(nla[NFNLA_HOOK_HOOKNUM]));
Tainted varhooknum
Call siteline 405 — passes hooknum to nfnl_hook_entries_head()
Call snippethead = nfnl_hook_entries_head(family, hooknum, net, name);
Subscript (in callee)[] line 290
Sink snippethook_head = rcu_dereference(net->nf.hooks_ipv4[hook]);
Possibly guardedyes (heuristic)
Dismissed: Line 288 checks `hook >= ARRAY_SIZE(net->nf.hooks_ipv4)` and returns ERR_PTR(-EINVAL) before line 290 accesses hooks_ipv4[hook]. No counterexample exists: any hook value that reaches line 290 satisfies hook < ARRAY_SIZE(hooks_ipv4).

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

CategoryCat C — server value → array subscript
Taint sourcentohl() line 392
Taint snippethooknum = ntohl(nla_get_be32(nla[NFNLA_HOOK_HOOKNUM]));
Tainted varhooknum
Call siteline 405 — passes hooknum to nfnl_hook_entries_head()
Call snippethead = nfnl_hook_entries_head(family, hooknum, net, name);
Subscript (in callee)[] line 295
Sink snippethook_head = rcu_dereference(net->nf.hooks_ipv6[hook]);
Possibly guardedyes (heuristic)
Dismissed: Line 293 checks `hook >= ARRAY_SIZE(net->nf.hooks_ipv6)` and returns ERR_PTR(-EINVAL) before line 295 accesses hooks_ipv6[hook]. No counterexample exists.

Finding #3 — Category C — cross-function via nfnl_hook_entries_head() — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 392
Taint snippethooknum = ntohl(nla_get_be32(nla[NFNLA_HOOK_HOOKNUM]));
Tainted varhooknum
Call siteline 405 — passes hooknum to nfnl_hook_entries_head()
Call snippethead = nfnl_hook_entries_head(family, hooknum, net, name);
Subscript (in callee)[] line 301
Sink snippethook_head = rcu_dereference(net->nf.hooks_arp[hook]);
Possibly guardedyes (heuristic)
Dismissed: Line 299 checks `hook >= ARRAY_SIZE(net->nf.hooks_arp)` and returns ERR_PTR(-EINVAL) before line 301 accesses hooks_arp[hook]. No counterexample exists.

Finding #4 — Category C — cross-function via nfnl_hook_entries_head() — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 392
Taint snippethooknum = ntohl(nla_get_be32(nla[NFNLA_HOOK_HOOKNUM]));
Tainted varhooknum
Call siteline 405 — passes hooknum to nfnl_hook_entries_head()
Call snippethead = nfnl_hook_entries_head(family, hooknum, net, name);
Subscript (in callee)[] line 308
Sink snippethook_head = rcu_dereference(net->nf.hooks_bridge[hook]);
Possibly guardedyes (heuristic)
Dismissed: Line 307 checks `hook >= ARRAY_SIZE(net->nf.hooks_bridge)` and returns ERR_PTR(-EINVAL) before line 308 accesses hooks_bridge[hook]. No counterexample exists.

nft_cmp_select_ops() — net/netfilter/nft_cmp.c BUG confidence=medium

The function reads a user-supplied register identifier as u32 but stores it in u8, causing silent truncation. The truncated value is used only for ops-path selection here; actual register validation happens in nft_cmp_init(). The truncation could cause wrong ops selection but is not a direct memory-safety issue.

Finding #1 — Category H — BUG integer_overflow

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 414
Taint snippetsreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
Tainted varsreg
Truncationline 414: 32 → 8-bit u8
Sink snippetsreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: Wrong expression ops (nft_cmp16_fast_ops) selected for a register that is not actually a valid aligned NFT_REG32; could cause incorrect nftables rule evaluation or a mismatch between select_ops and init behavior leading to unexpected kernel behavior
Fix: Declare 'sreg' as u32 (not u8) to preserve the full 32-bit value before performing register range checks, e.g.: u32 sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG])); This prevents a value like 0x108 from truncating to 0x08 and falsely matching a valid register.

nft_reg_to_type() — net/netfilter/nft_immediate.c BUG confidence=medium

The value from nla_get_be32() is genuinely user-supplied netlink data. The 32-bit ntohl() result is silently truncated to u8 before the NFT_REG_VERDICT comparison. This can cause register 256 (0x100) to be misidentified as NFT_REG_VERDICT (0), leading to wrong data type selection (NFT_DATA_VERDICT instead of NFT_DATA_VALUE). The impact is a logic error rather than direct memory corruption, since reg is only used for the equality comparison and not as an array index in this function.

Finding #1 — Category H — BUG integer_overflow

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 37
Taint snippetreg = ntohl(nla_get_be32(nla));
Tainted varreg
Truncationline 37: 32 → 8-bit u8
Sink snippetreg = ntohl(nla_get_be32(nla));
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: A userspace process specifying register number 256 (0x100) would have it silently truncated to 0, misidentifying it as NFT_REG_VERDICT; subsequent nft_data_init() called with wrong type may fail unexpectedly or process data as verdict type incorrectly, potentially causing unexpected rule behavior or -EINVAL from type mismatch in later validation.
Fix: Use u32 (not u8) for reg: 'u32 reg = ntohl(nla_get_be32(nla));' to preserve the full 32-bit value before comparison. Alternatively, compare the raw be32 value directly against cpu_to_be32(NFT_REG_VERDICT) without converting to host byte order and truncating.

xt_data_to_user() — net/netfilter/x_tables.c FP confidence=high

The function xt_data_to_user() is a kernel-internal helper that copies xtables match/target data to userspace. The 'usersize' and 'size' parameters are passed in by kernel code (from struct xt_match/xt_target fields like .usersize and .matchsize/.targetsize), which are statically initialized by kernel modules — not read from userspace or from network packets. The taint source identified by the scanner (copy_to_user itself) is a false alarm; the scanner appears to be treating the destination of copy_to_user as a taint source, which is not meaningful here. The 'usersize' value comes from kernel-internal struct fields set at module load time by trusted kernel code, not from user-supplied data. The function also ensures aligned_size >= usersize semantics (the caller is responsible for passing consistent values). This is a well-established kernel utility function with no user-controlled size issue.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 319
Taint snippetif (copy_to_user(dst, src, usersize))
Tainted varusersize
Unvalidated sizecopy_to_user() arg 2 line 319 — size usersize
Sink snippetif (copy_to_user(dst, src, usersize))
Possibly guardedno
Dismissed: The scanner misidentifies 'usersize' as tainted, apparently by treating copy_to_user() itself as a taint source. In reality, 'usersize' is a kernel-internal value derived from struct xt_match/xt_target fields (e.g., .usersize, .matchsize), which are statically initialized by kernel modules at compile/load time — not supplied by users or network peers. The callers of xt_data_to_user() are kernel functions like xt_match_to_user() and xt_target_to_user() that pass these kernel-internal constants. No counterexample can be constructed because the values are not attacker-controlled. This is a false positive.

xt_obj_to_user() — net/netfilter/x_tables.c FP confidence=high

The function xt_obj_to_user() copies kernel-internal data TO userspace. The 'name' parameter is a kernel-internal string (e.g., a match/target module name like 'tcp', 'ACCEPT') whose length is determined by strlen() on a kernel-owned buffer. The copy_to_user destination 'pname' is a userspace buffer. The size argument strlen(name)+1 is NOT user-supplied or server-supplied — it is computed from a kernel-internal string. The scanner incorrectly flagged this because copy_to_user() itself is a taint source in its model, but the size here comes from the kernel's own 'name' string, not from user input. The real concern would be whether pname's userspace buffer is large enough to hold the name, but that is the caller's responsibility and the name strings in xt_tables are module names bounded by XT_EXTENSION_MAXNAMELEN (29 bytes), making overflow of any properly-sized userspace field practically impossible.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 302
Taint snippetif (copy_to_user(pname, name, strlen(name) + 1))
Tainted varstrlen(name) + 1
Unvalidated sizecopy_to_user() arg 2 line 302 — size strlen(name) + 1
Sink snippetif (copy_to_user(pname, name, strlen(name) + 1))
Possibly guardedno
Dismissed: The 'name' parameter is a kernel-internal string (match/target name) stored in kernel memory, not user-supplied or server-supplied data. strlen(name)+1 is computed from a kernel-owned buffer whose content is controlled by the kernel (populated from registered xt_match/xt_target structures with names bounded by XT_EXTENSION_MAXNAMELEN). The scanner treats copy_to_user() as a taint source and then flags the same copy_to_user() as a sink, which is a circular false positive. No counterexample is constructible because the name strings originate from kernel module registration, not external input.

netlbl_af4list_audit_addr() — net/netlabel/netlabel_addrlist.c FP confidence=high

The flagged loop is a pure bit-counting operation on a u32 local variable with no memory access whatsoever. The loop shifts mask_val left and counts iterations; since mask_val is a 32-bit unsigned integer, the loop terminates in at most 32 iterations regardless of input. There is no buffer, no array, no pointer dereference — the scanner has incorrectly classified an arithmetic loop as a buffer traversal.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 314
Taint snippetu32 mask_val = ntohl(mask);
Tainted varmask_val
Loopwhile_loop line 322
Sink snippetwhile (mask_val > 0) {
Possibly guardedyes (heuristic)
Dismissed: The loop performs bitwise left-shifts on a u32 local variable (mask_val) and counts how many shifts are needed to drain all bits. After at most 32 iterations the u32 becomes 0 and the loop exits. No buffer, pointer, or array is involved — there is no possible OOB access. No counterexample can be constructed because the loop bound is structurally limited to 32 by the width of u32. The taint analysis tool incorrectly categorized this arithmetic bit-counting loop as a buffer-bounds problem. False positive.

netlbl_af6list_audit_addr() — net/netlabel/netlabel_addrlist.c FP confidence=high

The flagged loop is a bit-counting loop (popcount-style) that left-shifts a u32 until it becomes zero. It performs no array/buffer access inside the loop body, and terminates in at most 32 iterations by the nature of finite-width integer arithmetic. The scanner incorrectly categorized this as a buffer-iteration loop controlled by an unbounded server-supplied count.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 360
Taint snippetmask_val = ntohl(mask->s6_addr32[iter]);
Tainted varmask_val
Loopwhile_loop line 361
Sink snippetwhile (mask_val > 0) {
Possibly guardedno
Dismissed: The loop 'while (mask_val > 0) { mask_val <<= 1; mask_len++; }' is a bit-counting loop, not a buffer traversal. It accesses no array elements — it only shifts a u32 register variable left on each iteration. Since mask_val is a 32-bit unsigned integer, the loop terminates in at most 32 iterations regardless of the input value: any u32 left-shifted 32 times becomes 0. No counterexample can be constructed because the loop body contains no memory access. mask_len accumulates at most 128 total (32 from the first while + 32 from this loop + up to 64 from s6_addr32 traversal), well within u32 range. This is a false positive — the static scanner confused a bit-width-bounded arithmetic loop for an unbounded buffer iteration loop.

qrtr_ns_worker() — net/qrtr/ns.c MIXED confidence=high

The packet is received from the network via kernel_recvmsg, so pkt->cmd is genuinely server-supplied. Finding #1 (line 674 subscript) lacks a bounds check — the check `cmd < ARRAY_SIZE(qrtr_ctrl_pkt_strings)` appears on line 673 as the condition of the if-statement, but the subscript on line 674 IS inside that condition (short-circuit evaluation means line 674 is only reached when the check passes). However, finding #2 (line 675) is also inside the same if-block and is therefore also guarded. Both uses of `cmd` as an array subscript are guarded by `cmd < ARRAY_SIZE(qrtr_ctrl_pkt_strings)` on line 673, which is the correct and sufficient bounds check. The scanner incorrectly marked finding #1 as 'Possibly guarded: no' — the check is present and tight.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele32_to_cpu() line 672
Taint snippetcmd = le32_to_cpu(pkt->cmd);
Tainted varcmd
Subscript[] line 674
Sink snippetqrtr_ctrl_pkt_strings[cmd])
Possibly guardedno
Dismissed: The scanner marked this 'Possibly guarded: no', but looking at lines 673-676 carefully: the condition on line 673 is `cmd < ARRAY_SIZE(qrtr_ctrl_pkt_strings) && qrtr_ctrl_pkt_strings[cmd]`. The subscript on line 674 (`qrtr_ctrl_pkt_strings[cmd]`) is the second operand of the short-circuit &&, evaluated only when `cmd < ARRAY_SIZE(qrtr_ctrl_pkt_strings)` is true. Therefore the bounds check IS present and sufficient. No counterexample exists: any value of cmd >= ARRAY_SIZE would cause the first condition to be false, preventing evaluation of the subscript.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcele32_to_cpu() line 672
Taint snippetcmd = le32_to_cpu(pkt->cmd);
Tainted varcmd
Subscript[] line 675
Sink snippettrace_qrtr_ns_message(qrtr_ctrl_pkt_strings[cmd],
Possibly guardedyes (heuristic)
Dismissed: The use on line 675 (`qrtr_ctrl_pkt_strings[cmd]` as argument to trace_qrtr_ns_message) is inside the body of the if-statement whose condition already verified `cmd < ARRAY_SIZE(qrtr_ctrl_pkt_strings) && qrtr_ctrl_pkt_strings[cmd]`. Both the range bound and the null-pointer check are satisfied before this line executes. No counterexample exists.

rds_add_bound() — net/rds/bind.c FP confidence=high

The function validates the port value against reserved values (0, RDS_FLAG_PROBE_PORT) before use. The flagged sink in __rds_create_bind_key() uses sizeof(port) as the memcpy size argument, which is sizeof(__be16) == 2 — a compile-time constant entirely independent of the tainted port value. The scanner incorrectly treated the tainted 'port' parameter as influencing sizeof(port).

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

CategoryCat B — server value → size/alloc argument
Taint sourcebe16_to_cpu() line 102
Taint snippetrover = be16_to_cpu(*port);
Tainted varrover
Call siteline 117 — passes rover to __rds_create_bind_key()
Call snippet__rds_create_bind_key(key, addr, cpu_to_be16(rover),
Sink (in callee)memcpy() line 61 (arg 2, role=size)
Sink snippetmemcpy(key, &port, sizeof(port));
Possibly guardedyes (heuristic)
Dismissed: The memcpy size argument in __rds_create_bind_key() is sizeof(port) where port is of type __be16 — this evaluates to the compile-time constant 2, not the runtime value of port/rover. The taint cannot affect the size argument. Additionally, *port comes from user-space sockaddr (sin->sin_port), not a server/network response, making this doubly a false positive. No counterexample exists because sizeof() never uses the runtime value of its argument.

rds_cong_clear_bit() — net/rds/cong.c BUG confidence=high

The function rds_cong_clear_bit() accepts a __be16 port value and converts it to a CPU-native value via be16_to_cpu(). The port is a network-supplied 16-bit value (0–65535). It is divided by RDS_CONG_MAP_PAGE_BITS (which equals PAGE_SIZE*8 = 32768) to compute index i. The maximum port value 65535 gives i = 65535/32768 = 1 (integer division), which equals 1. RDS_CONG_MAP_PAGES is defined as 2 (since the congestion map covers 65536 bits = 2 pages). So the array m_page_addrs[] has exactly 2 entries (indices 0 and 1). The maximum i is 1, which is within bounds. However, there is no explicit bounds check in the code, and the safety relies entirely on the implicit constraint that be16_to_cpu() returns at most 65535, making i at most 1. If the array size RDS_CONG_MAP_PAGES ever changes, or if the value were not strictly 16-bit, an OOB could occur. Additionally, port=0 is technically valid and gives i=0. The implicit arithmetic safety is real but fragile and undocumented.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcebe16_to_cpu() line 321
Taint snippeti = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
Tainted vari
Subscript[] line 324
Sink snippetclear_bit_le(off, (void *)map->m_page_addrs[i]);
Possibly guardedno
Dismissed: Counterexample attempt: be16_to_cpu(port) has maximum value 65535. With RDS_CONG_MAP_PAGE_BITS = PAGE_SIZE*8 = 32768, i = 65535/32768 = 1. RDS_CONG_MAP_PAGES = 2, so m_page_addrs[] has indices 0 and 1. No counterexample exists — i is always 0 or 1, both in bounds. The finding is technically a false positive from a strict safety standpoint, but the implicit reliance on arithmetic constraints without any explicit guard is a latent fragility issue. Marking real_bug=false and impact=none as no OOB is actually possible with current constants.

rds_cong_set_bit() — net/rds/cong.c BUG confidence=high

The function rds_cong_set_bit() takes a __be16 port value, converts it to host byte order, and uses the result divided by RDS_CONG_MAP_PAGE_BITS as an array index into map->m_page_addrs[]. No bounds check is performed on 'i' before the array access. A port value is a 16-bit quantity (0–65535), and RDS_CONG_MAP_PAGE_BITS is typically PAGE_SIZE*8 (32768), yielding i values of 0 or 1 for well-formed ports. However, RDS_CONG_MAP_PAGES defines the size of m_page_addrs[], and if a caller supplies a crafted or unexpected port value, or if the constants differ from expectations, an out-of-bounds array access is possible. The port parameter comes from network packets in the RDS receive path, making this genuinely server/peer-supplied.

Finding #1 — Category C — BUG oob_write

CategoryCat C — server value → array subscript
Taint sourcebe16_to_cpu() line 307
Taint snippeti = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
Tainted vari
Subscript[] line 310
Sink snippetset_bit_le(off, (void *)map->m_page_addrs[i]);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds or wild pointer dereference in rds_cong_set_bit() when a peer sends a crafted or unexpected port value causing 'i' to exceed the bounds of map->m_page_addrs[]
Fix: Add a bounds check before the array access: if (i >= RDS_CONG_MAP_PAGES) { WARN_ON_ONCE(1); return; } — where RDS_CONG_MAP_PAGES is the declared size of m_page_addrs[]. This ensures 'i' is within valid array bounds before use.
CVE pattern: Array index out-of-bounds via network-supplied 16-bit value without range validation

rds_cong_test_bit() — net/rds/cong.c FP confidence=high

The port is a __be16 value, so be16_to_cpu() is mathematically bounded to [0, 65535]. With RDS_CONG_MAP_PAGE_BITS = PAGE_SIZE*8 = 32768 bits/page, the index i = port_val / 32768 can only be 0 or 1. The m_page_addrs array is sized as RDS_CONG_MAP_PAGES = DIV_ROUND_UP(65536/8, PAGE_SIZE) = 2, exactly covering all possible port values. No out-of-bounds access is possible by construction.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcebe16_to_cpu() line 332
Taint snippeti = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
Tainted vari
Subscript[] line 335
Sink snippetreturn test_bit_le(off, (void *)map->m_page_addrs[i]);
Possibly guardedno
Dismissed: Although no explicit bounds check is present, the type constraint of __be16 limits be16_to_cpu(port) to [0, 65535]. Dividing by RDS_CONG_MAP_PAGE_BITS (32768) yields at most index 1. The m_page_addrs array has exactly 2 entries (RDS_CONG_MAP_PAGES=2), so i is always in [0,1]. No counterexample can be constructed — the arithmetic is safe by design matching the full __be16 port space.

rds_ib_inc_copy_to_user() — net/rds/ib_recv.c BUG confidence=medium

The function uses a peer-supplied h_len field to drive fragment list traversal without validating it against the actual number of fragments/bytes received. If h_len exceeds actual received data, the list_entry() call will walk past the end of the fragment list, producing an invalid pointer.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcebe32_to_cpu() line 546
Taint snippetlen = be32_to_cpu(inc->i_hdr.h_len);
Tainted varlen
Loopwhile_loop line 548
Sink snippetwhile (iov_iter_count(to) && copied < len) {
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: General protection fault or KASAN use-after-free report in rds_ib_inc_copy_to_user when list_entry() dereferences past the end of ii_frags list; potential kernel panic or info disclosure from invalid page fragment pointer
Fix: Validate h_len against the actual number of bytes present in ii_frags (sum of fragment sizes or count*RDS_FRAG_SIZE) before entering the loop. Add a check such as: if (len > actual_frag_bytes) return -EINVAL; Alternatively, check list boundary (if frag->f_item.next == &ibinc->ii_frags) before advancing the fragment pointer.
CVE pattern: Peer-supplied length field driving linked-list traversal without bounds — similar to various network driver OOB patterns where received length fields are not validated against actual buffer/fragment counts

rds_ib_xmit() — net/rds/ib_send.c FP confidence=high

The server-supplied h_len value (tainted i) is passed to rds_ib_ring_alloc(), which caps the allocation at min(requested, available_slots) where available_slots = ring->w_nr - used. The returned work_alloc is therefore bounded by the ring size. The loop at line 652 iterates work_alloc times and accesses ic->i_sends[pos], where i_sends is sized to the ring capacity (w_nr). The ring's modular arithmetic also keeps pos within bounds. No OOB access is possible regardless of the h_len value.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcebe32_to_cpu() line 524
Taint snippeti = DIV_ROUND_UP(be32_to_cpu(rm->m_inc.i_hdr.h_len), RDS_FRAG_SIZE);
Tainted vari
Loopdo_loop line 652
Sink snippetdo {
Possibly guardedno
Dismissed: Although h_len is genuinely network-supplied, rds_ib_ring_alloc() acts as a truncating gate: it returns min(val, avail) where avail <= ring->w_nr. work_alloc is therefore bounded by the ring size, and ic->i_sends is allocated with ring->w_nr entries. No counterexample exists: any h_len value, however large, results in work_alloc bounded by ring->w_nr, keeping all i_sends[] accesses in bounds. The additional check at line 542 (work_alloc == 0 → return -ENOMEM) further validates the lower bound.

rds_message_inc_copy_to_user() — net/rds/message.c BUG confidence=medium

The function reads h_len from an incoming message header (network-supplied) and uses it to control a loop that advances a scatter-gather pointer without bounds-checking the sg array. If h_len exceeds the actual bytes in the sg list, sg++ can walk past the allocated array.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcebe32_to_cpu() line 526
Taint snippetlen = be32_to_cpu(rm->m_inc.i_hdr.h_len);
Tainted varlen
Loopwhile_loop line 532
Sink snippetwhile (iov_iter_count(to) && copied < len) {
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in rds_message_inc_copy_to_user when a malicious peer sends a message with h_len larger than the actual scatter-gather data; could also cause kernel panic or info disclosure via sg_page() on out-of-bounds sg entry
Fix: Track the number of sg elements (rm->data.op_nents) and add a check before advancing sg: if the sg pointer would exceed rm->data.op_sg + rm->data.op_nents, break out of the loop or return -EMSGSIZE. Also validate len against the total bytes in the sg list before entering the loop.
CVE pattern: Missing scatter-gather array bounds check when iterating with network-supplied length

rfkill_fop_read() — net/rfkill/core.c FP confidence=high

The tainted variable 'sz' is not user-supplied or server-supplied — it is computed entirely within the kernel using min_t() on sizeof(ev->ev) (a compile-time constant), the user-supplied count argument (the destination buffer size the user declared), and data->max_size (a kernel-internal field). The copy_to_user() call is therefore safe: sz is bounded above by sizeof(ev->ev), which is the exact size of the source object being copied. The scanner appears to have flagged 'sz' because 'count' (a user-supplied argument) flows into it, but after two min_t() operations the value cannot exceed sizeof(ev->ev), making it impossible to read beyond the source struct or write beyond what the user declared as their buffer size.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 1272
Taint snippetif (copy_to_user(buf, &ev->ev, sz))
Tainted varsz
Unvalidated sizecopy_to_user() arg 2 line 1272 — size sz
Sink snippetif (copy_to_user(buf, &ev->ev, sz))
Possibly guardedno
Dismissed: sz = min_t(unsigned long, sizeof(ev->ev), count) caps sz at sizeof(ev->ev) (a compile-time constant, the size of struct rfkill_event). The second min_t with data->max_size can only further reduce sz. Therefore sz <= sizeof(ev->ev) always holds before copy_to_user, preventing any over-read of the source buffer. The user-controlled value 'count' only influences sz downward. No counterexample exists where sz exceeds the source object size. False positive.

rxrpc_preparse_xdr() — net/rxrpc/key.c FP confidence=high

The function employs a rigorous two-phase approach: a full validation pass (lines 302-369) walks all data using pointer 'p' with per-step datalen checks and verifies datalen==0 at the end, then a processing pass (lines 375-412) re-traverses using 'xdr'. All loop bounds (len, paddedlen, ntoken) are validated against datalen before use. The callee functions (rxrpc_preparse_xdr_rxkad, rxrpc_preparse_xdr_yfs_rxgk) additionally validate their 'toklen' parameter internally before using derived values in allocations and memcpy calls. No genuine missing validation was found.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 320
Taint snippetlen = ntohl(*xdr++);
Tainted varlen
Loopfor_loop line 329
Sink snippetfor (loop = 0; loop < len; loop++)
Possibly guardedyes (heuristic)
Dismissed: len is bounded 1..AFSTOKEN_CELL_MAX at line 321. paddedlen=(len+3)&~3 is checked against datalen at line 325 (paddedlen>datalen → not_xdr). Since cp points into a buffer of size datalen and paddedlen≤datalen, loop indices 0..len-1 and len..paddedlen-1 are all within the buffer. No counterexample possible: any len that passes the guard satisfies paddedlen≤datalen, so cp[loop] is always in-bounds.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 320
Taint snippetlen = ntohl(*xdr++);
Tainted varpaddedlen
Loopfor_loop line 332
Sink snippetfor (; loop < paddedlen; loop++)
Possibly guardedyes (heuristic)
Dismissed: paddedlen derives from len (server-supplied) but is checked against datalen at line 325 before the loop at line 332. The loop runs from len to paddedlen-1 inclusive, all within the validated buffer range. No counterexample exists because paddedlen≤datalen is enforced before reaching the loop.

Finding #3 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 343
Taint snippetntoken = ntohl(*xdr++);
Tainted varloop
Loopdo_loop line 352
Sink snippetdo {
Possibly guardedno
Dismissed: loop=ntoken, bounded 1..AFSTOKEN_MAX at line 346. Inside the do-loop, per-iteration checks: datalen<8 guard (line 353), toklen<20||toklen>datalen||paddedlen>datalen guard (line 360). These per-iteration bounds checks terminate the loop before any OOB access, making the iteration count itself irrelevant to safety. No counterexample: any iteration that would exceed the buffer is caught by the inner datalen checks.

Finding #4 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 343
Taint snippetntoken = ntohl(*xdr++);
Tainted varntoken
Loopdo_loop line 375
Sink snippetdo {
Possibly guardedyes (heuristic)
Dismissed: The second do-loop (line 375) uses ntoken bounded 1..AFSTOKEN_MAX. More importantly, the first validation loop (lines 352-365) already walked all ntoken tokens using identical arithmetic (same base pointer region, same toklen/paddedlen per step) with full per-step bounds checks, and line 368 verifies datalen==0 (no leftover bytes). This constitutes a prior full-traversal validation that completely protects the second loop. False positive by protection pattern (c).

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 376
Taint snippettoklen = ntohl(*xdr++);
Tainted vartoklen
Call siteline 387 — passes toklen to rxrpc_preparse_xdr_rxkad()
Call snippetret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);
Sink (in callee)kzalloc() line 82 (arg 0, role=size)
Sink snippettoken->kad = kzalloc(plen, GFP_KERNEL);
Possibly guardedno
Dismissed: toklen at line 376 was pre-validated by the first loop (toklen≥20 and fits within original buffer). Inside rxrpc_preparse_xdr_rxkad: checks toklen>8*4, extracts tktlen=ntohl(xdr[7]), validates tktlen≤AFSTOKEN_RK_TIX_MAX and toklen≥8*4+tktlen. kzalloc at line 82 uses plen=sizeof(*token)+sizeof(*token->kad)+tktlen which is bounded by AFSTOKEN_RK_TIX_MAX. Cannot construct counterexample that passes all guards yet causes oversized allocation.

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 376
Taint snippettoklen = ntohl(*xdr++);
Tainted vartoklen
Call siteline 387 — passes toklen to rxrpc_preparse_xdr_rxkad()
Call snippetret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);
Sink (in callee)memcpy() line 96 (arg 2, role=size)
Sink snippetmemcpy(&token->kad->ticket, &xdr[8], tktlen);
Possibly guardedyes (heuristic)
Dismissed: memcpy at line 96 uses tktlen as size. tktlen is validated: tktlen≤AFSTOKEN_RK_TIX_MAX (line 69) and toklen≥8*4+tktlen (line 71). The destination buffer token->kad->ticket is allocated with tktlen bytes (plen includes tktlen). Source xdr[8] is valid because toklen≥8*4+tktlen ensures at least tktlen bytes after xdr[8]. No counterexample possible.

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 376
Taint snippettoklen = ntohl(*xdr++);
Tainted vartoklen
Call siteline 390 — passes toklen to rxrpc_preparse_xdr_yfs_rxgk()
Call snippetret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);
Sink (in callee)kzalloc() line 213 (arg 0, role=size)
Sink snippettoken->rxgk = kzalloc(struct_size_t(struct rxgk_key, _key, raw_keylen), GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: toklen passed to rxrpc_preparse_xdr_yfs_rxgk is pre-validated by the first traversal loop. Inside the callee: raw_keylen bounded by AFSTOKEN_GK_KEY_MAX (line 186), keylen size checked against toklen (line 189), kzalloc at line 213 uses struct_size_t based on raw_keylen which is bounded. Cannot construct counterexample passing all guards.

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 376
Taint snippettoklen = ntohl(*xdr++);
Tainted vartoklen
Call siteline 390 — passes toklen to rxrpc_preparse_xdr_yfs_rxgk()
Call snippetret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);
Sink (in callee)kzalloc() line 243 (arg 0, role=size)
Sink snippettoken->rxgk->ticket.data = kzalloc(tktlen, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: kzalloc at line 243 uses tktlen=round_up(raw_tktlen,4). raw_tktlen bounded by AFSTOKEN_GK_TOKEN_MAX (line 195). Exact size equality check at line 198 ensures consistency. No counterexample possible: tktlen is bounded and verified against toklen.

Finding #9 — Category A — cross-function via rxrpc_preparse_xdr_yfs_rxgk() — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohl() line 376
Taint snippettoklen = ntohl(*xdr++);
Tainted vartoklen
Call siteline 390 — passes toklen to rxrpc_preparse_xdr_yfs_rxgk()
Call snippetret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);
Sink (in callee)memcpy() line 246 (arg 1, role=pointer)
Sink snippetmemcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len);
Possibly guardedno
Dismissed: memcpy at line 246 copies ticket.len=raw_tktlen bytes from ticket pointer into allocated tktlen-byte buffer. raw_tktlen≤AFSTOKEN_GK_TOKEN_MAX, ticket pointer is computed as xdr+(6*2+1+keylen/4+1) and the exact size equality check (line 198) ensures ticket region plus key region equals toklen, so ticket is within the validated buffer. No counterexample possible.

rxrpc_preparse_xdr_rxkad() — net/rxrpc/key.c FP confidence=high

The function validates tktlen at lines 69-72 before any allocation or copy. Line 69 checks tktlen <= AFSTOKEN_RK_TIX_MAX (upper bound on value), and line 71-72 checks toklen >= 8*4 + tktlen (ensuring the source buffer is large enough). For finding #1 (kzalloc size): plen = sizeof(*token->kad) + tktlen, bounded by AFSTOKEN_RK_TIX_MAX. For finding #2 (memcpy): tktlen is bounded against the source buffer (toklen check) and the destination (token->kad->ticket is allocated as plen = sizeof(*token->kad)+tktlen, so ticket[] is tktlen bytes). Both checks are present and sufficient.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 67
Taint snippettktlen = ntohl(xdr[7]);
Tainted varplen
Sinkkzalloc() line 82 (arg 0, role=size)
Sink snippettoken->kad = kzalloc(plen, GFP_KERNEL);
Possibly guardedno
Dismissed: tktlen is checked against AFSTOKEN_RK_TIX_MAX at line 69 before being used in plen. plen = sizeof(*token->kad) + tktlen, so it is structurally bounded. No counterexample can be constructed: any tktlen > AFSTOKEN_RK_TIX_MAX is rejected before the allocation.

Finding #2 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 67
Taint snippettktlen = ntohl(xdr[7]);
Tainted vartktlen
Sinkmemcpy() line 96 (arg 2, role=size)
Sink snippetmemcpy(&token->kad->ticket, &xdr[8], tktlen);
Possibly guardedyes (heuristic)
Dismissed: Source buffer safety: line 71-72 ensures toklen >= 8*4 + tktlen, so xdr[8..8+tktlen-1] is within the passed-in xdr buffer. Destination safety: token->kad is allocated as sizeof(*token->kad)+tktlen bytes, and ticket[] is a flexible array at the end, so it holds exactly tktlen bytes. No counterexample can be constructed.

rxrpc_preparse_xdr_yfs_rxgk() — net/rxrpc/key.c FP confidence=high

The function has thorough validation: raw_keylen is capped by AFSTOKEN_GK_KEY_MAX before use in struct_size_t allocation; raw_tktlen is capped by AFSTOKEN_GK_TOKEN_MAX before use in kzalloc; an exact-equality check at line 198 ensures keylen+tktlen fits exactly within toklen; and the caller validates toklen fits within datalen. The ticket pointer arithmetic is covered by these combined constraints. No counterexample can be constructed that passes all guards yet causes OOB.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 184
Taint snippetraw_keylen = ntohl(key[-1]);
Tainted varraw_keylen
Sinkkzalloc() line 213 (arg 0, role=size)
Sink snippettoken->rxgk = kzalloc(struct_size_t(struct rxgk_key, _key, raw_keylen), GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: raw_keylen is checked against AFSTOKEN_GK_KEY_MAX at line 186 before being passed to struct_size_t(), which itself handles multiplication overflow. No counterexample: any raw_keylen > AFSTOKEN_GK_KEY_MAX is rejected before reaching the allocation.

Finding #2 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 193
Taint snippetraw_tktlen = ntohl(ticket[-1]);
Tainted vartktlen
Sinkkzalloc() line 243 (arg 0, role=size)
Sink snippettoken->rxgk->ticket.data = kzalloc(tktlen, GFP_KERNEL);
Possibly guardedyes (heuristic)
Dismissed: raw_tktlen is checked against AFSTOKEN_GK_TOKEN_MAX at line 195. tktlen = round_up(raw_tktlen, 4) is safe given the constant upper bound. The exact-equality check at line 198 further validates the total. No counterexample can pass all guards while causing undersized allocation.

Finding #3 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohl() line 184
Taint snippetraw_keylen = ntohl(key[-1]);
Tainted varticket
Sinkmemcpy() line 246 (arg 1, role=pointer)
Sink snippetmemcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len);
Possibly guardedno
Dismissed: The ticket pointer is derived from xdr with offset 13 + keylen/4 + 1 words. The exact-equality check at line 198 guarantees (6*2+2)*4 + keylen + tktlen == toklen, and the caller ensures toklen <= datalen (the original buffer size). Since raw_tktlen <= tktlen and the ticket data region is exactly tktlen bytes within the buffer, the memcpy source read is in-bounds.

rxgk_verify_authenticator() — net/rxrpc/rxgk.c FP confidence=high

rxgk_verify_authenticator() has solid validation discipline throughout: it checks minimum buffer lengths, validates app_len against remaining buffer, and critically validates call_count both against the protocol maximum (>4 check) and against the remaining buffer space (end-p < call_count check) before the loop. The conn->channels[] array access is safe because call_count is bounded to ≤4 matching RXRPC_MAXCALLS.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 1119
Taint snippetcall_count = ntohl(*p++);
Tainted varcall_count
Loopfor_loop line 1132
Sink snippetfor (i = 0; i < call_count; i++) {
Possibly guardedyes (heuristic)
Dismissed: Two independent guards protect this loop: (1) line 1124 rejects call_count > 4, bounding it to [0,4] which matches RXRPC_MAXCALLS for safe conn->channels[i] indexing; (2) line 1128 checks end-p < call_count ensuring the buffer contains at least call_count __be32 words before the loop begins. No counterexample can be constructed: any call_count that passes both guards will result in a loop that stays within both the buffer bounds and the channels array bounds.

rxgk_verify_response() — net/rxrpc/rxgk.c FP confidence=high

rxgk_verify_response() has solid layered validation: it checks buffer lengths before extracting fields, validates auth_len against remaining buffer before passing to rxgk_verify_authenticator(). Inside rxgk_verify_authenticator(), the server-supplied call_count is validated both against a maximum of 4 (matching RXRPC's 4-channel limit) and against the remaining buffer size before being used as a loop bound. The scanner traced taint from auth_len through to the loop but did not recognize the intervening call_count > 4 guard and end-p < call_count guard that make the loop safe.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 1205
Taint snippetauth_len = ntohl(xauth_len);
Tainted varauth_len
Call siteline 1254 — passes auth_len to rxgk_verify_authenticator()
Call snippetret = rxgk_verify_authenticator(conn, krb5, skb, auth, auth_len);
Loopfor_loop line 1132
Sink snippetfor (i = 0; i < call_count; i++) {
Possibly guardedyes (heuristic)
Dismissed: The loop variable is not auth_len itself but call_count, which is separately validated at line 1124 (call_count > 4 aborts) and line 1128 (end - p < call_count aborts). No counterexample exists: call_count is bounded to [0,4] and buffer is confirmed to hold at least call_count __be32 entries before the loop. rxgk_verify_authenticator() is the validation function — accesses inside it are the validation logic, not vulnerable sinks.

rxgk_yfs_decode_ticket() — net/rxrpc/rxgk_app.c FP confidence=high

The function validates klen against ticket_len at line 66 before any memory operations. The guard `klen > ticket_len - 10*sizeof(__be32)` establishes klen <= ticket_len-40, ensuring both source reads (from ticket buffer) and destination writes (into the precisely-sized payload allocation) stay in bounds. The allocation size payload_len is structurally derived from the validated klen and ticket_len, and xdr_round_up only adds alignment padding. All five findings are false positives protected by this gate.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 64
Taint snippetklen = ntohl(tmp[1]);
Tainted varpayload_len
Sinkkzalloc() line 75 (arg 0, role=size)
Sink snippetpayload = kzalloc(payload_len, GFP_NOFS);
Possibly guardedno
Dismissed: klen is bounded by the check at line 66: klen <= ticket_len - 40. payload_len = (19*4 + xdr_round_up(klen) + 4) + xdr_round_up(ticket_len). Since klen <= ticket_len <= UINT_MAX and ticket_len is a kernel-controlled unsigned int (from network buffer length), the allocation is properly sized. No counterexample can be constructed where the guard passes but the allocation is dangerously sized relative to subsequent use.

Finding #2 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohl() line 64
Taint snippetklen = ntohl(tmp[1]);
Tainted varticket
Sinkmemcpy() line 84 (arg 0, role=pointer)
Sink snippetmemcpy(ticket, buffer, ticket_len);
Possibly guardedno
Dismissed: ticket = payload + pre_ticket_len. The destination is the tail portion of the payload allocation, which was sized as pre_ticket_len + xdr_round_up(ticket_len). memcpy copies ticket_len bytes into this region — exactly fits. klen taint influences pre_ticket_len but payload is allocated large enough to hold both regions.

Finding #3 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohl() line 64
Taint snippetklen = ntohl(tmp[1]);
Tainted varklen
Sinkmemcpy() line 117 (arg 2, role=size)
Sink snippetmemcpy(q, ticket + sizeof(__be32) * 2, klen);
Possibly guardedyes (heuristic)
Dismissed: Source: ticket+8 to ticket+8+klen. Since klen <= ticket_len-40, and ticket has ticket_len bytes, reading klen bytes at offset 8 stays within ticket buffer (klen+8 <= ticket_len-32 < ticket_len). Destination: q is within pre_ticket_len region of payload, which was allocated with xdr_round_up(klen) bytes for exactly this copy. No counterexample possible.

Finding #4 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohl() line 64
Taint snippetklen = ntohl(tmp[1]);
Tainted varq
Sinkmemcpy() line 117 (arg 0, role=pointer)
Sink snippetmemcpy(q, ticket + sizeof(__be32) * 2, klen);
Possibly guardedno
Dismissed: q = payload + 5*4 + 14*4 = payload + 76. pre_ticket_len = 19*4 + xdr_round_up(klen) + 4 >= 80 bytes, so q+xdr_round_up(klen) bytes is within the pre_ticket_len region. The destination pointer is well within the allocated payload buffer.

Finding #5 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohl() line 64
Taint snippetklen = ntohl(tmp[1]);
Tainted varticket
Sinkmemcpy() line 117 (arg 1, role=pointer)
Sink snippetmemcpy(q, ticket + sizeof(__be32) * 2, klen);
Possibly guardedno
Dismissed: Source pointer ticket+sizeof(__be32)*2 = ticket+8. Reading klen bytes: since klen <= ticket_len-40, offset 8+klen <= ticket_len-32 < ticket_len, so the read stays within the ticket buffer. Same validation as finding #3.

rxkad_verify_packet() — net/rxrpc/rxkad.c FP confidence=high

The scanner flagged a 32-bit to 16-bit truncation at line 476. The note in the scanner's own finding states: 'flag as false positive if the RHS expression uses masking (& 0xFF, & 0xFFFF) or right-shift that limits the value to the destination width before assignment.' The RHS is `(y >> 16) & 0xffff`, which explicitly masks to 16 bits before assignment to the u16 variable. The shift by 16 followed by AND with 0xffff means only the upper 16 bits of y are extracted, and the result is guaranteed to fit in a u16. There is no truncation hazard here — the masking is intentional and correct. Additionally, the subsequent check `if (cksum == 0) cksum = 1;` and the comparison `if (cksum != sp->hdr.cksum)` are straightforward equality checks, not bounds checks that could be bypassed by a wider value.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 476
Taint snippetcksum = (y >> 16) & 0xffff;
Tainted varcksum
Truncationline 476: 32 → 16-bit u16
Sink snippetcksum = (y >> 16) & 0xffff;
Possibly guardedno
Dismissed: The scanner's own note says to flag as false positive when masking limits the value to the destination width. The expression `(y >> 16) & 0xffff` explicitly masks to exactly 16 bits before assigning to `u16 cksum`. No counterexample exists where the assignment produces a value outside the u16 range, because the AND with 0xffff mathematically constrains the result to [0, 65535]. The subsequent use of `cksum` is only for an equality comparison against `sp->hdr.cksum` (also a checksum value), with no array indexing or allocation sizing involved. This is a false positive.

rxkad_verify_packet_1() — net/rxrpc/rxkad.c FP confidence=high

The flagged truncation is intentional and safe. The code computes 'buf >> 16', which on a 32-bit value yields at most 16 bits of data (bits 31..16 shifted down to bits 15..0), so the result always fits in a u16 without loss. The subsequent XOR and masking with 0xffff further confirm that only a 16-bit check value is expected. This is a cryptographic checksum comparison, not a bounds calculation, so there is no OOB risk from the truncation.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 377
Taint snippetcheck = buf >> 16;
Tainted varcheck
Truncationline 377: 32 → 16-bit u16
Sink snippetcheck = buf >> 16;
Possibly guardedno
Dismissed: The RHS expression 'buf >> 16' shifts a 32-bit value right by 16 bits, producing a value in the range [0, 0xFFFF]. Assigning this to a u16 is lossless — no bits are discarded. The scanner note says to flag as false positive when a right-shift limits the value to the destination width, which is exactly the case here. Additionally, the check value is only used in a cryptographic equality comparison (check != 0 after XOR), not as an array index, allocation size, or pointer offset, so even if truncation occurred it would cause no memory safety issue.

rxkad_verify_packet_2() — net/rxrpc/rxkad.c FP confidence=high

The scanner flagged a 32-to-16-bit truncation of `check = buf >> 16`. However, this is intentional and safe: `buf` is a 32-bit value from `ntohl(sechdr->data_size)`, and the upper 16 bits are extracted via `buf >> 16`. After the right-shift, the value is guaranteed to fit in 16 bits (the upper 16 bits of a 32-bit value, after shifting right by 16, always yields a value in [0, 65535]). The assignment to `u16 check` is thus a safe narrowing. The subsequent XOR and mask (`check ^= seq ^ call->call_id; check &= 0xffff;`) further ensure it stays 16-bit. The check `if (check != 0)` is a correct integrity verification. No counterexample can be constructed where the truncation causes a security bypass — the truncation IS the intended protocol check (extracting the high 16 bits of a 32-bit field).

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 427
Taint snippetcheck = buf >> 16;
Tainted varcheck
Truncationline 427: 32 → 16-bit u16
Sink snippetcheck = buf >> 16;
Possibly guardedno
Dismissed: The right-shift `buf >> 16` on a 32-bit value always produces a value that fits in 16 bits (range 0–65535), so the assignment to `u16 check` is not a lossy truncation in any security-relevant sense. The scanner's concern that 'a later bounds check on check may pass even when the original value would not' is inapplicable here: the high 16 bits of `buf` are extracted deliberately to form a checksum, and the check `if (check != 0)` tests exactly the right quantity. No counterexample exists where the truncation allows an invalid packet to pass verification while a non-truncated check would reject it, because the protocol defines the checksum field as exactly these 16 bits.

sctp_association_init() — net/sctp/associola.c BUG confidence=high

The ep->auth_hmacs_list and ep->auth_chunk_list are set from local socket options (user-space via setsockopt), not directly from network packets. However, their param_hdr.length fields are user-controlled and used as memcpy size arguments into fixed-size destination buffers (asoc->c.auth_hmacs and asoc->c.auth_chunks in the sctp_cookie struct). No bounds check against the destination buffer size is performed before the memcpy, enabling a heap buffer overflow.

Finding #1 — Category B — BUG oob_write

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 264
Taint snippetmemcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list,
Tainted varntohs(ep->auth_hmacs_list->param_hdr.len
Sinkmemcpy() line 264 (arg 2, role=size)
Sink snippetmemcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list,
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_association_init; heap corruption if auth_hmacs_list->param_hdr.length exceeds sizeof(asoc->c.auth_hmacs)
Fix: Before the memcpy, validate that ntohs(ep->auth_hmacs_list->param_hdr.length) <= sizeof(asoc->c.auth_hmacs) and is >= sizeof(struct sctp_paramhdr). If not, either truncate or fail initialization.
CVE pattern: User-controlled length field used in memcpy into fixed-size destination without bounds check; similar to classic SCTP parameter overflow patterns

Finding #2 — Category B — BUG oob_write

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 267
Taint snippetmemcpy(asoc->c.auth_chunks, ep->auth_chunk_list,
Tainted varntohs(ep->auth_chunk_list->param_hdr.len
Sinkmemcpy() line 267 (arg 2, role=size)
Sink snippetmemcpy(asoc->c.auth_chunks, ep->auth_chunk_list,
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_association_init; heap corruption if auth_chunk_list->param_hdr.length exceeds sizeof(asoc->c.auth_chunks)
Fix: Before the memcpy, validate that ntohs(ep->auth_chunk_list->param_hdr.length) <= sizeof(asoc->c.auth_chunks) and is >= sizeof(struct sctp_paramhdr). If not, either truncate or fail initialization.
CVE pattern: User-controlled length field used in memcpy into fixed-size destination without bounds check; similar to classic SCTP parameter overflow patterns

__sctp_auth_cid() — net/sctp/auth.c BUG confidence=high

The function checks for zero-length but does not validate that ntohs(param->param_hdr.length) is within the actual received/allocated buffer size. The computed 'len' drives array indexing into param->chunks[] with no upper bound tied to actual memory allocation, enabling out-of-bounds reads with a crafted peer parameter.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 556
Taint snippetlen = ntohs(param->param_hdr.length) - sizeof(struct sctp_paramhdr);
Tainted varlen
Loopfor_loop line 564
Sink snippetfor (i = 0; !found && i < len; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in __sctp_auth_cid; kernel may also crash or disclose heap memory depending on what lies beyond the param buffer
Fix: After computing len, validate it against the actual size of the param buffer: e.g., if the param was received as part of an INIT chunk, ensure ntohs(param->param_hdr.length) does not exceed the enclosing chunk's remaining length. At minimum, cap len to the known allocation size: 'if (ntohs(param->param_hdr.length) < sizeof(struct sctp_paramhdr)) return 0; len = ntohs(param->param_hdr.length) - sizeof(struct sctp_paramhdr); if (len > known_param_buf_size - sizeof(struct sctp_paramhdr)) return 0;'
CVE pattern: Server-supplied length field used as loop bound without buffer-size validation — similar to classic SCTP parameter length OOB read patterns

sctp_auth_asoc_get_hmac() — net/sctp/auth.c MIXED confidence=high

The function reads peer-supplied HMAC parameter data from a network packet. Finding #1 is a real bug: n_elt is derived from a server-supplied length field and is used to bound array iteration over hmacs->hmac_ids[] without validating that n_elt * 2 bytes actually fit within the received buffer — a large server-supplied length could cause OOB reads of hmac_ids[]. Findings #2 and #3 are false positives: sctp_hmac_supported() validates 'id' against ARRAY_SIZE(sctp_hmac_list) before any array access, and the return statement at line 480 is guarded by that check.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 475
Taint snippetn_elt = (ntohs(hmacs->param_hdr.length) -
Tainted varn_elt
Loopfor_loop line 477
Sink snippetfor (i = 0; i < n_elt; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_auth_asoc_get_hmac — reading hmac_ids[] beyond the end of the peer_hmacs parameter buffer if the server supplies a crafted length field larger than the actual data
Fix: Before the loop, validate that n_elt does not exceed what the buffer can hold: compute max_elts = (ntohs(hmacs->param_hdr.length) - sizeof(struct sctp_paramhdr)) / sizeof(__be16) and clamp n_elt to min(n_elt, max_elts), AND verify that ntohs(hmacs->param_hdr.length) >= sizeof(struct sctp_paramhdr) to prevent underflow. The actual peer_hmacs allocation size should also be checked against n_elt * sizeof(__be16).
CVE pattern: Server-supplied length field controlling loop iteration count without buffer bounds validation — similar to various SCTP parameter parsing OOB reads

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 478
Taint snippetid = ntohs(hmacs->hmac_ids[i]);
Tainted varid
Subscript[] line 480
Sink snippetreturn &sctp_hmac_list[id];
Possibly guardedno
Dismissed: The access at line 480 (return &sctp_hmac_list[id]) is only reached when sctp_hmac_supported(id) returns true at line 479. sctp_hmac_supported() checks id < ARRAY_SIZE(sctp_hmac_list) before any array access, so the subscript is bounded. No counterexample exists that passes the guard and causes OOB. False positive.

Finding #3 — Category C — cross-function via sctp_hmac_supported() — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 478
Taint snippetid = ntohs(hmacs->hmac_ids[i]);
Tainted varid
Call siteline 479 — passes id to sctp_hmac_supported()
Call snippetif (sctp_hmac_supported(id))
Subscript (in callee)[] line 44
Sink snippetsctp_hmac_list[hmac_id].hmac_len != 0;
Possibly guardedno
Dismissed: sctp_hmac_supported() is itself the validator: it checks hmac_id < ARRAY_SIZE(sctp_hmac_list) at line 43 before accessing sctp_hmac_list[hmac_id] at line 44. The array access inside sctp_hmac_supported() IS the validation logic — a classic false positive per pattern #2 in the review guidelines. No OOB is possible here.

sctp_auth_asoc_set_default_hmac() — net/sctp/auth.c MIXED confidence=high

Finding #1 is a real bug: n_params is derived from a network-supplied length field without validating it against the actual buffer size, so the loop can iterate beyond the hmac_ids array. Finding #2 is a false positive: sctp_hmac_supported() IS the validation function — it bounds-checks hmac_id against ARRAY_SIZE(sctp_hmac_list) before indexing, so the array access inside it is the validation logic, not a vulnerable sink.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 534
Taint snippetn_params = (ntohs(hmacs->param_hdr.length) -
Tainted varn_params
Loopfor_loop line 536
Sink snippetfor (i = 0; i < n_params; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_auth_asoc_set_default_hmac — reading hmac_ids[i] beyond the end of the received packet buffer when length field is inflated
Fix: Before the loop, validate that n_params does not exceed the actual number of elements present in the received parameter. Specifically, cap n_params to (actual_buffer_or_param_length - sizeof(struct sctp_paramhdr)) / sizeof(__be16), where actual_buffer_or_param_length is passed in by the caller or derived from the chunk bounds — not blindly trusted from hmacs->param_hdr.length. For example: size_t max_params = (chunk_end - hmacs->hmac_ids) / sizeof(__be16); if (n_params > max_params) n_params = max_params;
CVE pattern: Network-supplied length field used as loop bound without validation against actual buffer size — similar pattern to CVE-2014-3673 (SCTP parameter length OOB)

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 537
Taint snippetid = ntohs(hmacs->hmac_ids[i]);
Tainted varid
Call siteline 538 — passes id to sctp_hmac_supported()
Call snippetif (sctp_hmac_supported(id)) {
Subscript (in callee)[] line 44
Sink snippetsctp_hmac_list[hmac_id].hmac_len != 0;
Possibly guardedno
Dismissed: sctp_hmac_supported() is itself the validation function. It checks 'hmac_id < ARRAY_SIZE(sctp_hmac_list)' before indexing sctp_hmac_list[hmac_id]. No counterexample exists: any hmac_id >= ARRAY_SIZE(sctp_hmac_list) returns false immediately, so the array access is always safe. The access inside sctp_hmac_supported() is the validation logic, not a vulnerable sink — classic false positive per pattern 2/4.

sctp_auth_asoc_verify_hmac_id() — net/sctp/auth.c BUG confidence=medium

The function reads `hmacs->param_hdr.length` from what appears to be a network-received SCTP association parameter structure. The `n_elt` value is derived from `ntohs()` on that length field without any validation against the actual allocated size of `asoc->c.auth_hmacs`. If a malicious peer sends an auth_hmacs parameter with a crafted length field, `n_elt` could exceed the actual number of valid elements, causing `__sctp_auth_find_hmacid()` to read beyond the allocated buffer. However, there may be upstream validation in the SCTP parameter parsing path that constrains this value — the confidence is medium rather than high because the full parsing call chain is not visible here.

Finding #1 — Category F — cross-function via __sctp_auth_find_hmacid() — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 511
Taint snippetn_elt = (ntohs(hmacs->param_hdr.length) -
Tainted varn_elt
Call siteline 514 — passes n_elt to __sctp_auth_find_hmacid()
Call snippetreturn __sctp_auth_find_hmacid(hmacs->hmac_ids, n_elt, hmac_id);
Loopfor_loop line 490
Sink snippetfor (i = 0; i < n_elts; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in __sctp_auth_find_hmacid() — kernel reads hmac_ids[] beyond the end of the allocated auth_hmacs buffer
Fix: Before computing n_elt, validate that `ntohs(hmacs->param_hdr.length)` is at least `sizeof(struct sctp_paramhdr)` and does not exceed the actual allocated size of `asoc->c.auth_hmacs`. Cap n_elt: e.g., `u16 raw_len = ntohs(hmacs->param_hdr.length); if (raw_len < sizeof(struct sctp_paramhdr) || raw_len > sizeof(asoc->c.auth_hmacs)) return 0; n_elt = (raw_len - sizeof(struct sctp_paramhdr)) >> 1;`
CVE pattern: Network-supplied length field used as loop bound without buffer bounds check — similar to classic SCTP/DCCP parameter parsing OOB reads

sctp_auth_ep_add_chunkid() — net/sctp/auth.c BUG confidence=high

The function uses an equality check (==) instead of a greater-than-or-equal check (>=) to guard the array subscript. Additionally, integer underflow in nchunks is possible if param_len < sizeof(struct sctp_paramhdr). Both issues allow the guard to be bypassed, leading to OOB write via p->chunks[nchunks].

Finding #1 — Category C — BUG oob_write

CategoryCat C — server value → array subscript
Taint sourcentohs() line 673
Taint snippetparam_len = ntohs(p->param_hdr.length);
Tainted varnchunks
Subscript[] line 678
Sink snippetp->chunks[nchunks] = chunk_id;
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_auth_ep_add_chunkid; heap corruption potentially leading to privilege escalation or kernel panic
Fix: Replace the equality check with a proper range check: (1) validate param_len >= sizeof(struct sctp_paramhdr) before computing nchunks to prevent underflow; (2) change 'if (nchunks == SCTP_AUTH_MAX_CHUNKS)' to 'if (nchunks >= SCTP_AUTH_MAX_CHUNKS)' to catch any out-of-range value, not just exactly the maximum.
CVE pattern: Integer underflow leading to OOB array write — similar pattern to various SCTP parameter parsing CVEs (e.g., CVE-2014-3673 style off-by-one/equality-instead-of-GTE checks)

sctp_auth_make_key_vector() — net/sctp/auth.c BUG confidence=high

The function extracts lengths from network-supplied SCTP parameter headers and uses them as memcpy sizes without verifying that these lengths are bounded by the actual source buffer sizes. The destination allocation is exactly the sum of these lengths, so OOB writes are impossible, but OOB reads from source buffers (random, chunks, hmacs) are possible if a peer sets a parameter length larger than the actual parameter data. Findings about 'new' being tainted (Category A/E on new->data) and cross-function findings about sctp_auth_create_key() are false positives: 'new' is kernel-allocated and sctp_auth_create_key() validates its argument internally.

Finding #1 — Category B — BUG oob_read

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varrandom_len
Sinkmemcpy() line 207 (arg 2, role=size)
Sink snippetmemcpy(new->data, random, random_len);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_auth_make_key_vector; memcpy reads beyond the actual random parameter buffer if random->param_hdr.length > actual buffer size
Fix: Validate random_len >= sizeof(sctp_random_param) and random_len <= actual received buffer size for the random parameter before using it as a copy size.
CVE pattern: SCTP parameter length field OOB read

Finding #2 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varnew
Sinkmemcpy() line 207 (arg 0, role=pointer)
Sink snippetmemcpy(new->data, random, random_len);
Possibly guardedno
Dismissed: False positive: 'new' is kernel-allocated via kmalloc. The taint propagation to new->data is spurious. The pointer arithmetic stays within the allocated region since total allocation equals the sum of all copy sizes.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varnew
Pointer derefnew->data line 207
Sink snippetmemcpy(new->data, random, random_len);
Possibly guardedno
Dismissed: False positive: new is a kernel-allocated struct, not a server-supplied pointer. Accessing new->data is safe after successful kmalloc.

Finding #4 — Category B — BUG oob_read

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 199
Taint snippetchunks_len = ntohs(chunks->param_hdr.length);
Tainted varchunks_len
Sinkmemcpy() line 211 (arg 2, role=size)
Sink snippetmemcpy(new->data + offset, chunks, chunks_len);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_auth_make_key_vector; memcpy reads beyond the actual chunks parameter buffer if chunks->param_hdr.length > actual buffer size
Fix: Validate chunks_len >= sizeof(sctp_chunks_param) and chunks_len <= actual received buffer size for the chunks parameter before using it as a copy size.
CVE pattern: SCTP parameter length field OOB read

Finding #5 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varnew
Sinkmemcpy() line 211 (arg 0, role=pointer)
Sink snippetmemcpy(new->data + offset, chunks, chunks_len);
Possibly guardedno
Dismissed: False positive: new is kernel-allocated. offset = random_len at this point, and the allocation is random_len + chunks_len + hmacs_len, so new->data + offset is within bounds for the chunks copy.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varnew
Pointer derefnew->data line 211
Sink snippetmemcpy(new->data + offset, chunks, chunks_len);
Possibly guardedno
Dismissed: False positive: new is kernel-allocated; new->data at offset random_len is within the allocation boundary.

Finding #7 — Category B — BUG oob_read

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 197
Taint snippethmacs_len = ntohs(hmacs->param_hdr.length);
Tainted varhmacs_len
Sinkmemcpy() line 215 (arg 2, role=size)
Sink snippetmemcpy(new->data + offset, hmacs, hmacs_len);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_auth_make_key_vector; memcpy reads beyond the actual hmacs parameter buffer if hmacs->param_hdr.length > actual buffer size
Fix: Validate hmacs_len >= sizeof(sctp_hmac_algo_param) and hmacs_len <= actual received buffer size for the hmacs parameter before using it as a copy size.
CVE pattern: SCTP parameter length field OOB read

Finding #8 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varnew
Sinkmemcpy() line 215 (arg 0, role=pointer)
Sink snippetmemcpy(new->data + offset, hmacs, hmacs_len);
Possibly guardedno
Dismissed: False positive: new is kernel-allocated. Destination pointer new->data + offset is within allocated bounds.

Finding #9 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varnew
Pointer derefnew->data line 215
Sink snippetmemcpy(new->data + offset, hmacs, hmacs_len);
Possibly guardedno
Dismissed: False positive: new is kernel-allocated; new->data access at offset = random_len + chunks_len is within the allocated region.

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

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varlen
Call siteline 203 — passes len to sctp_auth_create_key()
Call snippetnew = sctp_auth_create_key(len, gfp);
Sink (in callee)kmalloc() line 68 (arg 0, role=size_mul_overflow)
Sink snippetkey = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp);
Possibly guardedyes (heuristic)
Dismissed: False positive: sctp_auth_create_key() explicitly checks key_len > (INT_MAX - sizeof(struct sctp_auth_bytes)) and returns NULL on overflow. The allocation size is fully validated inside the callee. No counterexample possible — the guard caps the value before kmalloc.

Finding #11 — Category E — cross-function via sctp_auth_create_key() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varlen
Call siteline 203 — passes len to sctp_auth_create_key()
Call snippetnew = sctp_auth_create_key(len, gfp);
Pointer dereflen-> line 72
Sink snippetkey->len = key_len;
Possibly guardedno
Dismissed: False positive: key->len = key_len is only reached after kmalloc succeeds, which means key is a valid kernel-allocated pointer. The taint on key_len does not make key->len unsafe to write.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 196
Taint snippetrandom_len = ntohs(random->param_hdr.length);
Tainted varlen
Call siteline 203 — passes len to sctp_auth_create_key()
Call snippetnew = sctp_auth_create_key(len, gfp);
Pointer dereflen-> line 73
Sink snippetrefcount_set(&key->refcnt, 1);
Possibly guardedno
Dismissed: False positive: refcount_set(&key->refcnt, 1) operates on a kernel-allocated struct after successful kmalloc. The tainted key_len value only determines allocation size, not the struct pointer validity.

__sctp_rcv_lookup_endpoint() — net/sctp/input.c FP confidence=high

The hash value is computed by sctp_ep_hashfn(), which is a dedicated hash function that constrains its output to the valid range of sctp_ep_hashtable indices. The lport value, while derived from a network packet, is passed through sctp_ep_hashfn() which performs a modulo operation (or equivalent bitmask) against the hash table size, guaranteeing the result is within bounds. This is a standard hash-table lookup pattern in the kernel where the hash function itself serves as the bounds constraint.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 853
Taint snippethash = sctp_ep_hashfn(net, ntohs(lport));
Tainted varhash
Subscript[] line 854
Sink snippethead = &sctp_ep_hashtable[hash];
Possibly guardedno
Dismissed: The lport value (sin_port) is indeed server-supplied from the network packet, so ntohs() propagates taint. However, the value is immediately passed to sctp_ep_hashfn(), which computes 'hash % sctp_ep_hashsize' (or a bitmask equivalent). This constrains the result to [0, sctp_ep_hashsize-1], which is precisely the valid index range for sctp_ep_hashtable. No counterexample can be constructed: regardless of what lport value arrives from the network (including 0 or 65535), sctp_ep_hashfn() maps it into bounds. The scanner flagged the taint flow but did not model the hash function's range-constraining postcondition, making this a false positive.

sctp_acked() — net/sctp/outqueue.c FP confidence=medium

Both findings involve server-supplied data from SACK packets. Finding #1 is a real truncation but results in a logic error (possible incorrect ack determination), not memory safety. Finding #2's loop count risk is mitigated by SCTP chunk-level validation that occurs earlier in the receive path before sctp_check_transmitted is ever called — the SACK chunk length is validated against num_gap_ack_blocks before the chunk reaches this processing stage.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 1797
Taint snippettsn_offset = tsn - ctsn;
Tainted vartsn_offset
Truncationline 1797: 32 → 16-bit u16
Sink snippettsn_offset = tsn - ctsn;
Possibly guardedno
Dismissed: The truncation of tsn-ctsn to 16-bit tsn_offset is real, but gap block start/end fields are also 16-bit. If tsn-ctsn exceeds 0xFFFF, the truncated value might spuriously match a gap block, leading to incorrect ack logic — but no memory safety violation. This is a protocol correctness concern rather than a security vulnerability.

Finding #2 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1796
Taint snippetblocks = ntohs(sack->num_gap_ack_blocks);
Tainted varblocks
Loopfor_loop line 1798
Sink snippetfor (i = 0; i < blocks; ++i) {
Possibly guardedno
Dismissed: SCTP's standard receive path validates SACK chunk length against the number of gap ack blocks and duplicate TSNs in sctp_sf_eat_sack_6_2() before handing the SACK to outqueue processing. This prior full-path validation protects the loop. The call site shown does not display this earlier validation because it occurs several layers up in the receive path, making this a false positive consistent with pattern #3 (prior full-traversal/validation).

sctp_check_transmitted() — net/sctp/outqueue.c FP confidence=high

The static analyzer flagged tsn (from ntohl()) as a tainted loop bound inside sctp_acked(). However, sctp_acked() is itself a validation/query function: it checks whether a given TSN is acknowledged in the SACK. The 'blocks' loop bound inside sctp_acked() is controlled by sack->num_gap_ack_blocks (a separate server-supplied field), NOT by the tsn argument passed in. The tsn argument is only used to compute tsn_offset and compared against frags[i].gab.start/.end — it is not used as a loop bound at all. The loop iterates 'blocks' times regardless of tsn. The scanner confused 'tsn is passed to sctp_acked()' with 'tsn controls the loop bound', but the actual loop bound is 'blocks' (sack->num_gap_ack_blocks), not tsn. Furthermore, tchunk->subh.data_hdr->tsn is a TSN the local kernel previously assigned and stored in a chunk it sent — it is not a server-supplied value being used to index memory.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 1480
Taint snippettsn = ntohl(tchunk->subh.data_hdr->tsn);
Tainted vartsn
Call siteline 1481 — passes tsn to sctp_acked()
Call snippetif (sctp_acked(sack, tsn)) {
Loopfor_loop line 1798
Sink snippetfor (i = 0; i < blocks; ++i) {
Possibly guardedno
Dismissed: The tsn value at line 1480 is read from tchunk->subh.data_hdr->tsn, which is the TSN the local kernel assigned to an outgoing DATA chunk it constructed and transmitted. It is NOT a server-supplied value. Inside sctp_acked(), the tsn argument is used only to compute tsn_offset = tsn - ctsn and to compare against gap block boundaries — it does NOT control the loop bound. The loop bound is 'blocks = ntohs(sack->num_gap_ack_blocks)', which is a different field entirely. The scanner's analysis is incorrect: tsn does not flow into the loop bound (arg 0 of for_loop). No counterexample can be constructed because tsn is not the loop bound. This is a false positive.

sctp_outq_flush_data() — net/sctp/outqueue.c FP confidence=high

The scanner misidentifies the truncation: 'stream_state' receives '->state' (a small enum field of a stream struct), not a direct truncation of the 16-bit 'sid'. The 16-bit sid is used as an array index in SCTP_SO(), not stored in stream_state. Additionally, outgoing chunks have stream IDs set by the local kernel stack, not by a remote server. The real concern (unvalidated sid as array index) is a different issue not flagged here.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohs() line 1087
Taint snippet__u8 stream_state = SCTP_SO(&ctx->asoc->stream, sid)->state;
Tainted varstream_state
Truncationline 1087: 16 → 8-bit __u8
Sink snippet__u8 stream_state = SCTP_SO(&ctx->asoc->stream, sid)->state;
Possibly guardedno
Dismissed: The scanner incorrectly attributes the truncation: stream_state is assigned from SCTP_SO(...)->state (the state field of a sctp_stream_out struct, a small type), not directly from the 16-bit ntohs() result. No actual 16-bit→8-bit truncation of a meaningful value occurs. The chunks are outgoing data chunks with stream IDs set locally by the kernel, so the data is not server-supplied. No counterexample can be constructed for the stated truncation bug because the assignment path does not involve truncating the ntohs() result into stream_state.

sctp_outq_sack() — net/sctp/outqueue.c BUG confidence=high

The function reads gap_ack_blocks from a network-supplied SACK chunk via ntohs() and immediately uses it as an array index (gap_ack_blocks - 1) into frags[] without any bounds check. The only guard is `if (gap_ack_blocks)` which only checks for non-zero — it does not verify that gap_ack_blocks is within the actual received chunk length. A malicious peer can send a SACK chunk with num_gap_ack_blocks set to an arbitrarily large value, causing the array access frags[gap_ack_blocks - 1] to read memory far beyond the end of the received skb data.

Finding #1 — Category C — BUG oob_read

CategoryCat C — server value → array subscript
Taint sourcentohs() line 1275
Taint snippetgap_ack_blocks = ntohs(sack->num_gap_ack_blocks);
Tainted vargap_ack_blocks
Subscript[] line 1320
Sink snippethighest_tsn += ntohs(frags[gap_ack_blocks - 1].gab.end);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_outq_sack / kernel panic from reading beyond the end of the received SCTP chunk skb data
Fix: Before using gap_ack_blocks as an array index, validate it against the actual chunk length: ensure that sizeof(struct sctp_sackhdr) + gap_ack_blocks * sizeof(union sctp_sack_variable) <= (chunk->chunk_hdr->length - sizeof(struct sctp_chunkhdr)). For example: if (gap_ack_blocks > (ntohs(chunk->chunk_hdr->length) - sizeof(struct sctp_chunkhdr) - sizeof(struct sctp_sackhdr)) / sizeof(union sctp_sack_variable)) return -EINVAL;
CVE pattern: Out-of-bounds read via unchecked server-supplied count field used as array subscript — similar in class to CVE-2014-7841 and other SCTP chunk parsing OOB bugs

sctp_sack_update_unack_data() — net/sctp/outqueue.c FP confidence=medium

The num_gap_ack_blocks field is server-supplied, but SCTP validates SACK chunks via sctp_verify_sack() in the state machine (sctp_sf_eat_sack_6_2) before sctp_outq_sack() is ever called. That validator checks that the chunk length covers sizeof(sctp_sackhdr_t) + num_gap_ack_blocks*sizeof(gap_ack_block) + num_dup_tsns*4, so the loop in sctp_sack_update_unack_data() cannot iterate beyond the validated buffer. The static scanner missed this upstream validation gate.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1236
Taint snippetfor (i = 0; i < ntohs(sack->num_gap_ack_blocks); i++) {
Tainted var(inline)
Loopfor_loop line 1236
Sink snippetfor (i = 0; i < ntohs(sack->num_gap_ack_blocks); i++) {
Possibly guardedno
Dismissed: The SCTP state machine calls sctp_verify_sack() before sctp_outq_sack() is invoked. sctp_verify_sack() validates that the SACK chunk's length field is consistent with num_gap_ack_blocks and num_dup_tsns, establishing that the buffer is large enough for the loop. No counterexample can be constructed that passes sctp_verify_sack() yet causes OOB access in the loop — the upstream validation is a sufficient guard.

sctp_get_asconf_response() — net/sctp/sm_make_chunk.c BUG confidence=high

The function uses server-supplied chunk_hdr->length (via ntohs) to control loop iteration without validating it against the actual skb->len. Additionally, the per-element length field from the network is used to advance the pointer without minimum-size checks, enabling infinite loops or OOB reads.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 3429
Taint snippetasconf_ack_len = ntohs(asconf_ack->chunk_hdr->length) -
Tainted varasconf_ack_len
Loopwhile_loop line 3440
Sink snippetwhile (asconf_ack_len > 0) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_get_asconf_response; kernel reads past the end of skb->data when server-supplied chunk_hdr->length exceeds actual received data size
Fix: Cap asconf_ack_len to min(ntohs(asconf_ack->chunk_hdr->length) - sizeof(sctp_chunkhdr), asconf_ack->skb->len - sizeof(sctp_addiphdr)). Additionally, in the loop body, validate that 'length' from ntohs(asconf_ack_param->param_hdr.length) is at least sizeof(struct sctp_addip_param) before advancing the pointer, to prevent infinite loops and ensure the pointer stays within the buffer.
CVE pattern: SCTP chunk length field OOB read — similar to CVE-2014-3673/CVE-2014-3687 style SCTP chunk parsing vulnerabilities
The destination buffer is allocated using the same ntohs(init_chunk->chunk_hdr->length) value that is later used as the memcpy size, so destination OOB write is impossible by construction. For source OOB read, the SCTP receive path validates chunk lengths against actual skb data before delivering chunks to this code path. The finding is a false positive, though the implicit reliance on upstream validation for source bounds is worth documenting.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 1704
Taint snippetmemcpy(cookie + 1, init_chunk->chunk_hdr,
Tainted varntohs(init_chunk->chunk_hdr->length)
Sinkmemcpy() line 1704 (arg 2, role=size)
Sink snippetmemcpy(cookie + 1, init_chunk->chunk_hdr,
Possibly guardedno
Dismissed: The destination buffer is kzalloc'd with size = headersize + bodysize, where bodysize includes ntohs(init_chunk->chunk_hdr->length). So the destination always has enough room — no counterexample possible for OOB write. For OOB read from the source (init_chunk->chunk_hdr), the SCTP stack validates that chunk_hdr->length fits within the received skb during chunk parsing before this function is called. No counterexample found that would pass upstream validation yet cause OOB here.

sctp_process_asconf() — net/sctp/sm_make_chunk.c BUG confidence=medium

sctp_process_asconf() computes chunk_len from a server-supplied length field and then multiplies by 4 before passing to sctp_make_asconf_ack(). There are no bounds checks to ensure chunk_len is non-negative or that chunk_len*4 doesn't overflow. The flagged sink (ptr_deref at line 2999) is actually safe since retval is null-checked, but the underlying issue is an undersized or incorrectly-sized allocation due to unvalidated arithmetic on server-supplied data.

Finding #1 — Category E — cross-function via sctp_make_asconf_ack() — BUG undersized_alloc

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 3283
Taint snippetchunk_len = ntohs(asconf->chunk_hdr->length) -
Tainted varchunk_len
Call siteline 3304 — passes chunk_len to sctp_make_asconf_ack()
Call snippetasconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 4);
Pointer derefchunk_len-> line 2999
Sink snippetretval->subh.addip_hdr =
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: Heap corruption or BUG: KASAN: slab-out-of-bounds when writing ASCONF_ACK parameters into an undersized buffer, or integer overflow in chunk_len*4 causing wrong allocation size
Fix: Validate chunk_len after each subtraction to ensure it remains non-negative (return error if chunk_len < 0). Also check for integer overflow before computing chunk_len * 4, e.g., if (chunk_len < 0 || chunk_len > (INT_MAX/4)) return NULL/error. Ensure addr_param->p.length is validated against remaining buffer size before subtracting.
CVE pattern: Integer underflow in network-supplied length field leading to undersized allocation, similar to CVE-2014-4667 style SCTP length field issues

sctp_process_asconf_ack() — net/sctp/sm_make_chunk.c BUG confidence=medium

The function processes a locally-stored ASCONF chunk (kernel-built) but reads TLV lengths from it without proper bounds validation. The critical missing checks are: (1) no validation that addr_param->p.length is sane (>= sizeof(*addr_param) and <= asconf_len) before computing asconf_param, (2) no check that asconf_param->param_hdr.length > 0 in the loop, which can cause an infinite loop, (3) no check that asconf_param + sizeof(*asconf_param) stays within the skb buffer bounds. Finding #3 is a false positive on loop-bound characterization.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 3491
Taint snippetlength = ntohs(addr_param->p.length);
Tainted varasconf_param
Pointer derefasconf_param->param_hdr line 3529
Sink snippetasconf_param->param_hdr.type;
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_process_asconf_ack when addr_param->p.length is zero or exceeds buffer bounds, causing asconf_param to point outside the skb buffer
Fix: Validate that ntohs(addr_param->p.length) >= sizeof(*addr_param) and <= asconf_len before computing asconf_param. Inside the loop, similarly validate that ntohs(asconf_param->param_hdr.length) >= sizeof(*asconf_param) and that asconf_param + length stays within the original skb buffer before advancing the pointer.
CVE pattern: TLV length field not validated before pointer arithmetic — similar pattern to CVE-2014-3673 (SCTP OOB access)

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 3491
Taint snippetlength = ntohs(addr_param->p.length);
Tainted varasconf_param
Pointer derefasconf_param->param_hdr line 3542
Sink snippetlength = ntohs(asconf_param->param_hdr.length);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: Infinite loop or kernel panic if asconf_param->param_hdr.length is 0, causing asconf_len to never decrease; or OOB read if asconf_param advances past skb end
Fix: Before the length assignment at line 3542, verify that asconf_param is still within bounds (asconf_param + sizeof(*asconf_param) <= skb_tail_pointer(asconf->skb)), and that ntohs(asconf_param->param_hdr.length) >= sizeof(*asconf_param) to prevent zero-length infinite loops.
CVE pattern: TLV zero-length infinite loop — similar to multiple SCTP CVEs

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

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 3491
Taint snippetlength = ntohs(addr_param->p.length);
Tainted varasconf_param
Call siteline 3508 — passes asconf_param to sctp_get_asconf_response()
Call snippeterr_code = sctp_get_asconf_response(asconf_ack,
Loopwhile_loop line 3440
Sink snippetwhile (asconf_ack_len > 0) {
Possibly guardedno
Dismissed: False positive on loop-bound characterization. In sctp_get_asconf_response(), the while loop at line 3440 is bounded by asconf_ack_len (independently computed from asconf_ack->chunk_hdr->length), not by the tainted asconf_param pointer. The tainted asconf_param is only used to match crr_id — it controls which response is returned, not the iteration count. The real risk is the OOB pointer dereference of asconf_param itself (covered by findings #1 and #2).

Finding #4 — Category E — cross-function via sctp_asconf_param_success() — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 3491
Taint snippetlength = ntohs(addr_param->p.length);
Tainted varasconf_param
Call siteline 3517 — passes asconf_param to sctp_asconf_param_success()
Call snippetsctp_asconf_param_success(asoc, asconf_param);
Pointer derefasconf_param-> line 3366
Sink snippetaf = sctp_get_af_specific(param_type2af(addr_param->p.type));
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_asconf_param_success when asconf_param points beyond skb buffer, causing addr_param->p.type read from invalid memory
Fix: Validate that asconf_param + sizeof(*asconf_param) + sizeof(union sctp_addr_param) is within the skb buffer before calling sctp_asconf_param_success(). This is a consequence of the same missing bounds check in findings #1/#2.
CVE pattern: TLV length field not validated before pointer arithmetic

Finding #5 — Category E — cross-function via sctp_asconf_param_success() — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 3491
Taint snippetlength = ntohs(addr_param->p.length);
Tainted varasconf_param
Call siteline 3517 — passes asconf_param to sctp_asconf_param_success()
Call snippetsctp_asconf_param_success(asoc, asconf_param);
Pointer derefasconf_param-> line 3367
Sink snippetif (!af->from_addr_param(&addr, addr_param, htons(bp->port), 0))
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: NULL pointer dereference or OOB read in sctp_asconf_param_success when af is NULL (from invalid addr_param->p.type) or addr_param points outside buffer
Fix: Same fix as finding #4 — validate buffer bounds before calling sctp_asconf_param_success(). Note that sctp_get_af_specific() may return NULL for an invalid type, but the code checks af indirectly via the function pointer call without a NULL check shown (though from_addr_param dispatch may handle it).
CVE pattern: TLV length field not validated before pointer arithmetic

sctp_process_ext_param() — net/sctp/sm_make_chunk.c BUG confidence=high

sctp_process_ext_param() computes num_ext purely from the server-supplied param.p->length field without validating that the declared length fits within the actual received buffer. The call site in sctp_process_param() does not perform any length validation before the call for the SCTP_PARAM_SUPPORTED_EXT case. Additionally, if param.p->length is smaller than sizeof(struct sctp_paramhdr), the unsigned subtraction wraps around, producing a huge iteration count.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 2034
Taint snippet__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
Tainted varnum_ext
Loopfor_loop line 2037
Sink snippetfor (i = 0; i < num_ext; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_process_ext_param; reading beyond the packet buffer when a malicious peer sends SCTP_PARAM_SUPPORTED_EXT with an inflated or underflowing length field
Fix: Before computing num_ext, validate that ntohs(param.p->length) >= sizeof(struct sctp_paramhdr); then validate that sizeof(struct sctp_paramhdr) + num_ext does not exceed the actual buffer/chunk length passed to the function. Clamp or reject the parameter if the declared length exceeds the real data available. Example: if (ntohs(param.p->length) < sizeof(struct sctp_paramhdr)) return; num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); and ensure num_ext does not exceed the remaining validated buffer size.
CVE pattern: Server-supplied length field used as loop bound without buffer validation — similar pattern to various SCTP/network protocol OOB read CVEs

sctp_process_param() — net/sctp/sm_make_chunk.c FP confidence=high

sctp_process_param receives parameters already validated by sctp_walk_params in the caller. The loop iteration count 'sat' is derived from param.p->length which sctp_walk_params has already verified fits within the actual packet buffer. Therefore types[0..sat-1] lies within the validated buffer extent.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 2600
Taint snippetsat = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
Tainted varsat
Loopfor_loop line 2604
Sink snippetfor (i = 0; i < sat; ++i) {
Possibly guardedno
Dismissed: The sctp_walk_params macro in the caller (sctp_process_init) validates each parameter's length against the actual chunk buffer before yielding it. sat = (ntohs(param.p->length) - sizeof(struct sctp_paramhdr)) / sizeof(__u16) is therefore bounded by the real buffer size. Accessing param.sat->types[i] for i < sat stays within the validated parameter bounds. No counterexample is constructible because any inflated param.p->length would have caused sctp_walk_params to reject the parameter before it reached this function.

sctp_verify_ext_param() — net/sctp/sm_make_chunk.c BUG confidence=high

sctp_verify_ext_param() computes num_ext from a server-supplied length field without validating that the resulting iteration count stays within the actual bounds of the parameter buffer. Two issues: (1) unsigned underflow if length < sizeof(sctp_paramhdr), producing a huge num_ext; (2) even with a valid subtraction, num_ext is never checked against the actual bytes available in param.ext->chunks[], allowing out-of-bounds reads.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 2000
Taint snippet__u16 num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr);
Tainted varnum_ext
Loopfor_loop line 2005
Sink snippetfor (i = 0; i < num_ext; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_verify_ext_param when processing a malformed SCTP INIT/INIT-ACK with an oversized or undersized SUPPORTED_EXT parameter length field
Fix: Before the loop, validate that param.p->length >= sizeof(struct sctp_paramhdr) (to prevent underflow), then validate that num_ext fits within the actual parameter data: num_ext = ntohs(param.p->length) - sizeof(struct sctp_paramhdr); and ensure num_ext <= (actual_param_buffer_end - param.ext->chunks). A simple fix: if (ntohs(param.p->length) < sizeof(struct sctp_paramhdr)) return 1; and then clamp/check num_ext against the parameter's declared length vs. remaining buffer size passed from the caller.
CVE pattern: Server-supplied length field used as loop bound without bounds validation — similar to CVE-2014-0101 and other SCTP parameter parsing OOB reads

sctp_verify_param() — net/sctp/sm_make_chunk.c BUG confidence=high

sctp_verify_param() validates several parameter types for correct lengths, but the SCTP_PARAM_HMAC_ALGO case fails to validate that param.p->length >= sizeof(struct sctp_paramhdr) before computing n_elt, allowing underflow/wrap-around of the 16-bit arithmetic to produce a very large iteration count.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 2249
Taint snippetn_elt = (ntohs(param.p->length) -
Tainted varn_elt
Loopfor_loop line 2256
Sink snippetfor (i = 0; i < n_elt; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_verify_param / kernel crash reading past HMAC parameter buffer with a malformed SCTP INIT chunk
Fix: Before computing n_elt, validate that ntohs(param.p->length) >= sizeof(struct sctp_paramhdr). Then validate that n_elt * sizeof(__be16) <= ntohs(param.p->length) - sizeof(struct sctp_paramhdr). E.g.: u16 plen = ntohs(param.p->length); if (plen < sizeof(struct sctp_paramhdr)) { /* abort */ } n_elt = (plen - sizeof(struct sctp_paramhdr)) >> 1;
CVE pattern: Integer underflow leading to oversized loop iteration count from malformed network parameter length field

sctp_eat_data() — net/sctp/sm_statefuns.c FP confidence=high

Both call sites validate chunk length via sctp_chunk_length_valid() before calling sctp_eat_data(). Inside sctp_eat_data(), tsn undergoes sctp_tsnmap_check() which bounds-checks the TSN range. The flagged sink (retval->transport = chunk->transport) in sctp_make_abort_no_data() is completely independent of the tsn parameter - tsn is only used as a data payload via htonl(tsn), never as a pointer or index. The scanner made a spurious taint propagation connection.

Finding #1 — Category E — cross-function via sctp_make_abort_no_data() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 6548
Taint snippettsn = ntohl(data_hdr->tsn);
Tainted vartsn
Call siteline 6658 — passes tsn to sctp_make_abort_no_data()
Call snippeterr = sctp_make_abort_no_data(asoc, chunk, tsn);
Pointer dereftsn-> line 993
Sink snippetretval->transport = chunk->transport;
Possibly guardedyes (heuristic)
Dismissed: The tsn value is server-supplied but is only used as a 32-bit data payload in sctp_make_abort_no_data(). The code does: payload = htonl(tsn), then sctp_addto_chunk with sizeof(payload). The sink retval->transport = chunk->transport at line 993 dereferences 'chunk' (the received chunk pointer), which has no data-flow dependency on 'tsn'. The scanner incorrectly attributed the chunk->transport dereference to the tsn taint. No counterexample is possible because tsn never influences any pointer arithmetic or array indexing in this callee. This is a classic false positive from imprecise taint propagation that conflates all parameters of a function call.

sctp_sf_authenticate() — net/sctp/sm_statefuns.c FP confidence=medium

The function has reasonable validation: hmac_id is validated by sctp_auth_asoc_verify_hmac_id before array indexing; sig_len is constrained to equal hmac->hmac_len (a fixed small value) before memory operations. The main concern is the sctp_auth_chunk_verify call path which lacks an explicit chunk_length_valid check, potentially allowing integer underflow in sig_len computation.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 4436
Taint snippetsig_len = ntohs(chunk->chunk_hdr->length) -
Tainted varsig_len
Sinkmemset() line 4456 (arg 2, role=size)
Sink snippetmemset(digest, 0, sig_len);
Possibly guardedyes (heuristic)
Dismissed: In sctp_sf_eat_auth, sctp_chunk_length_valid guards against underflow, and sig_len != hmac->hmac_len constrains sig_len to a fixed small value. In sctp_auth_chunk_verify, no explicit chunk_length_valid is visible, but the memory operations are still bounded by hmac_len. No concrete counterexample could be constructed for the eat_auth path. The auth_chunk_verify path is slightly less protected but the data was previously parsed.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 4438
Taint snippethmac = sctp_auth_get_hmac(ntohs(auth_hdr->hmac_id));
Tainted varntohs(auth_hdr->hmac_id)
Call siteline 4438 — passes ntohs(auth_hdr->hmac_id) to sctp_auth_get_hmac()
Call snippethmac = sctp_auth_get_hmac(ntohs(auth_hdr->hmac_id));
Subscript (in callee)[] line 450
Sink snippetreturn &sctp_hmac_list[hmac_id];
Possibly guardedno
Dismissed: sctp_auth_asoc_verify_hmac_id() is called at line 4420 BEFORE sctp_auth_get_hmac() at line 4438, validating the hmac_id. This validator ensures the hmac_id is in the association's approved list, which should only contain valid IDs bounded by SCTP_AUTH_HMAC_ID_MAX. The array subscript in sctp_auth_get_hmac() is protected by this prior validation gate. No counterexample can be constructed that passes the validator but causes OOB.

sctp_sf_do_5_1B_init() — net/sctp/sm_statefuns.c FP confidence=high

The 'tainted' value len comes from ntohs(err_chunk->chunk_hdr->length), but err_chunk is a locally-constructed kernel ERROR chunk built by sctp_verify_init(), not a server-supplied buffer. The chunk_hdr->length was written by the kernel. Furthermore, even if len were server-supplied, the flagged sinks in sctp_make_init_ack() (lines 478, 482, 484) are field accesses on a freshly allocated retval chunk — they are NOT pointer dereferences offset by len. The static analyzer incorrectly propagated taint from len through the chunksize arithmetic to unrelated pointer dereferences on retval.

Finding #1 — Category E — cross-function via sctp_make_init_ack() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 442
Taint snippetlen = ntohs(err_chunk->chunk_hdr->length) -
Tainted varlen
Call siteline 445 — passes len to sctp_make_init_ack()
Call snippetrepl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
Pointer dereflen-> line 478
Sink snippetretval->transport =
Possibly guardedno
Dismissed: err_chunk is locally constructed by the kernel via sctp_verify_init(). The sink at line 478 (retval->transport) is a fixed field access on a freshly allocated chunk, not derived from len. Taint propagation is spurious.

Finding #2 — Category E — cross-function via sctp_make_init_ack() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 442
Taint snippetlen = ntohs(err_chunk->chunk_hdr->length) -
Tainted varlen
Call siteline 445 — passes len to sctp_make_init_ack()
Call snippetrepl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
Pointer dereflen-> line 482
Sink snippetretval->subh.init_hdr =
Possibly guardedno
Dismissed: Same as finding #1. retval->subh.init_hdr access at line 482 is on the locally allocated retval chunk, not offset by len. False positive due to spurious taint propagation through chunksize arithmetic.

Finding #3 — Category E — cross-function via sctp_make_init_ack() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 442
Taint snippetlen = ntohs(err_chunk->chunk_hdr->length) -
Tainted varlen
Call siteline 445 — passes len to sctp_make_init_ack()
Call snippetrepl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
Pointer dereflen-> line 484
Sink snippetretval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v);
Possibly guardedno
Dismissed: retval->param_hdr.v at line 484 uses addrs_len (not len/unkparam_len) as the size argument. The taint of len does not affect this pointer dereference. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 442
Taint snippetlen = ntohs(err_chunk->chunk_hdr->length) -
Tainted varlen
Call siteline 445 — passes len to sctp_make_init_ack()
Call snippetrepl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
Pointer dereflen-> line 516
Sink snippetretval->asoc = (struct sctp_association *) asoc;
Possibly guardedno
Dismissed: retval->asoc assignment at line 516 is a fixed field write on the locally allocated retval chunk. No relationship to len whatsoever. The static analyzer over-propagated taint. False positive.

sctp_sf_do_unexpected_init() — net/sctp/sm_statefuns.c FP confidence=high

The taint source is ntohs(err_chunk->chunk_hdr->length) where err_chunk is a locally kernel-constructed ERROR chunk, not a direct copy from a received network packet. Even treating it as tainted, the flagged sinks in sctp_make_init_ack() (lines 478, 482, 484, 516) are dereferences of 'retval', a locally allocated chunk struct returned by sctp_make_control(). The len/unkparam_len parameter influences the allocation size calculation but does not control the pointer being dereferenced at those specific lines. The scanner performed overly aggressive transitive taint propagation through the allocation function.

Finding #1 — Category E — cross-function via sctp_make_init_ack() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1665
Taint snippetlen = ntohs(err_chunk->chunk_hdr->length) -
Tainted varlen
Call siteline 1669 — passes len to sctp_make_init_ack()
Call snippetrepl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
Pointer dereflen-> line 478
Sink snippetretval->transport =
Possibly guardedno
Dismissed: err_chunk is kernel-constructed (built by sctp_verify_init to report unknown params). The sink at line 478 dereferences 'retval', a locally allocated chunk, not a pointer derived from len. False positive due to overly aggressive taint propagation through sctp_make_control() return value.

Finding #2 — Category E — cross-function via sctp_make_init_ack() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1665
Taint snippetlen = ntohs(err_chunk->chunk_hdr->length) -
Tainted varlen
Call siteline 1669 — passes len to sctp_make_init_ack()
Call snippetrepl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
Pointer dereflen-> line 482
Sink snippetretval->subh.init_hdr =
Possibly guardedno
Dismissed: Same as finding #1. The sink at line 482 (retval->subh.init_hdr) dereferences the locally allocated 'retval', not a pointer derived from len. False positive.

Finding #3 — Category E — cross-function via sctp_make_init_ack() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1665
Taint snippetlen = ntohs(err_chunk->chunk_hdr->length) -
Tainted varlen
Call siteline 1669 — passes len to sctp_make_init_ack()
Call snippetrepl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
Pointer dereflen-> line 484
Sink snippetretval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v);
Possibly guardedno
Dismissed: Same as finding #1. The sink at line 484 (retval->param_hdr.v) dereferences the locally allocated 'retval', not a pointer derived from len. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1665
Taint snippetlen = ntohs(err_chunk->chunk_hdr->length) -
Tainted varlen
Call siteline 1669 — passes len to sctp_make_init_ack()
Call snippetrepl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
Pointer dereflen-> line 516
Sink snippetretval->asoc = (struct sctp_association *) asoc;
Possibly guardedno
Dismissed: Same as finding #1. The sink at line 516 (retval->asoc) dereferences the locally allocated 'retval', not a pointer derived from len. False positive from transitive taint propagation.

sctp_get_port_local() — net/sctp/socket.c FP confidence=high

The value 'snum' comes from ntohs(addr->v4.sin_port), which is a user-supplied port number (not strictly server-supplied in the network-response sense). However, the array index is not 'snum' directly — it passes through sctp_phashfn(net, snum) which is a hash function. sctp_phashfn computes a bounded hash (modulo the hash table size), so the result is always within the bounds of sctp_port_hashtable regardless of what snum is. The scanner flagged snum as the subscript, but the actual subscript is the output of a bounded hash function. Additionally, in the snum==0 branch (line 8423), snum is replaced by 'rover' which is constrained to [low, high] by inet_sk_get_local_port_range and the loop guard. In the else branch (line 8461), snum is an unsigned short (0–65535) passed through sctp_phashfn which masks it to the hash table size. No OOB access is possible.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohs() line 8419
Taint snippetsnum = ntohs(addr->v4.sin_port);
Tainted varsnum
Subscript[] line 8468
Sink snippethead = &sctp_port_hashtable[sctp_phashfn(net, snum)];
Possibly guardedyes (heuristic)
Dismissed: The actual array subscript is sctp_phashfn(net, snum), not snum itself. sctp_phashfn computes a bounded hash modulo the hash table size (typically using a bitmask or modulo operation on the port number), so the index is always within bounds of sctp_port_hashtable. The scanner incorrectly attributed the subscript role to the raw 'snum' value rather than the bounded hash result. No counterexample can be constructed because the hash function output is inherently bounded. This is a false positive.

sctp_getsockopt_hmac_ident() — net/sctp/socket.c FP confidence=medium

ep->auth_hmacs_list is constructed internally by the SCTP authentication subsystem (sctp_auth_init_hmacs and related functions), not received from a remote peer. The param_hdr.length field is set by the kernel using htons() when building the local parameter list. Therefore, ntohs() reads back a kernel-written value, not server-supplied data. The loop bound num_idents reflects the actual number of HMAC identifiers the kernel stored in the structure, and the copy_to_user operations are additionally guarded by the data_len check against the user optlen.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 6974
Taint snippetdata_len = ntohs(hmacs->param_hdr.length) -
Tainted varnum_idents
Loopfor_loop line 6987
Sink snippetfor (i = 0; i < num_idents; i++) {
Possibly guardedno
Dismissed: ep->auth_hmacs_list is a kernel-internal structure initialized by sctp_auth_init_hmacs(). Its param_hdr.length is set by the kernel itself (not from any received network packet), so ntohs() here is reading back a locally-written value. num_idents therefore reflects the actual count of HMAC IDs stored in the array, making the loop safe. No counterexample can be constructed from external input. The check at line 6977 additionally ensures the user-space destination buffer is large enough for the copy_to_user operations.

sctp_getsockopt_local_addrs() — net/sctp/socket.c FP confidence=high

bytes_copied is an internally accumulated counter, not user/server-supplied data. It is bounded by space_left (the allocation size of addrs) through either explicit per-iteration space_left checks in the list loop or through sctp_copy_laddrs which receives space_left as its capacity limit. No counterexample can be constructed where bytes_copied exceeds sizeof(addrs).

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 6392
Taint snippetif (copy_to_user(to, addrs, bytes_copied)) {
Tainted varbytes_copied
Unvalidated sizecopy_to_user() arg 2 line 6392 — size bytes_copied
Sink snippetif (copy_to_user(to, addrs, bytes_copied)) {
Possibly guardedno
Dismissed: bytes_copied is kernel-computed, not user-supplied. In the list_for_each_entry path, each increment is guarded by 'if (space_left < addrlen) return -ENOMEM' and space_left is decremented accordingly, ensuring bytes_copied never exceeds the allocation size of addrs (space_left). In the sctp_copy_laddrs path, the same space_left capacity is passed as a bound parameter. No counterexample exists where bytes_copied > sizeof(addrs). The copy_to_user reads from a kernel buffer (addrs) bounded by space_left and writes to user space — no kernel OOB possible.

sctp_getsockopt_local_auth_chunks() — net/sctp/socket.c BUG confidence=high

The function computes num_chunks from a network-supplied length field without (a) checking for integer underflow when subtracting sizeof(sctp_paramhdr), and (b) bounding num_chunks against the actual size of the source buffer ch. The destination-side guard at line 7112 is present but insufficient because an underflowed num_chunks causes sizeof(sctp_authchunks)+num_chunks to wrap, potentially bypassing the check, and there is no source-buffer size validation at all.

Finding #1 — Category B — BUG oob_read

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 7111
Taint snippetnum_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr);
Tainted varnum_chunks
Sinkcopy_to_user() line 7115 (arg 2, role=size)
Sink snippetif (copy_to_user(to, ch->chunks, num_chunks))
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_getsockopt_local_auth_chunks (heap OOB read from ch->chunks with attacker-controlled length); potential kernel memory disclosure to userspace via copy_to_user
Fix: Before the subtraction, validate that ntohs(ch->param_hdr.length) >= sizeof(struct sctp_paramhdr). Additionally, validate that num_chunks does not exceed the actual allocated size of ch minus sizeof(sctp_paramhdr) (e.g., check against a stored length or a maximum constant). Use: u16 raw_len = ntohs(ch->param_hdr.length); if (raw_len < sizeof(struct sctp_paramhdr)) return -EINVAL; num_chunks = raw_len - sizeof(struct sctp_paramhdr); and then also bound num_chunks against the known maximum chunk list size.
CVE pattern: Integer underflow in length field subtraction leading to OOB read, similar to CVE-2021-3655 (SCTP information disclosure) pattern

sctp_getsockopt_peer_auth_chunks() — net/sctp/socket.c BUG confidence=medium

The function validates the destination (user buffer) side via the len check, but does not validate the source side: num_chunks is derived from a peer-supplied length field and used to read from ch->chunks without verifying that the allocation/received data actually contains num_chunks bytes. An integer underflow is mitigated by unsigned arithmetic causing the len check to catch it. The primary issue is OOB read of the kernel heap when the peer supplies a length field larger than the actual allocated chunk data.

Finding #1 — Category B — BUG oob_read

CategoryCat B — server value → size/alloc argument
Taint sourcentohs() line 7061
Taint snippetnum_chunks = ntohs(ch->param_hdr.length) - sizeof(struct sctp_paramhdr);
Tainted varnum_chunks
Sinkcopy_to_user() line 7065 (arg 2, role=size)
Sink snippetif (copy_to_user(to, ch->chunks, num_chunks))
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in sctp_getsockopt_peer_auth_chunks — reading beyond the allocated peer_chunks buffer when the peer supplies an inflated param_hdr.length value
Fix: Before computing num_chunks, validate that ntohs(ch->param_hdr.length) >= sizeof(struct sctp_paramhdr) (to prevent underflow) and that num_chunks does not exceed the actual allocated/received size of the ch buffer (i.e., the total parameter length as received on the wire). Add: if (ntohs(ch->param_hdr.length) < sizeof(struct sctp_paramhdr)) return -EINVAL; and ensure num_chunks is capped at the known-good size of ch.
CVE pattern: Heap OOB read via peer-controlled length field — similar in class to CVE-2021-3772 style SCTP parameter length issues

sctp_process_strreset_addstrm_in() — net/sctp/stream.c FP confidence=high

Both findings are false positives. The sequence-number guards at lines 867-870 tightly constrain `request_seq` to be within 2 of `asoc->strreset_inseq`, and the else-if at line 871 further restricts it to [strreset_inseq-2, strreset_inseq-1]. This means `i = asoc->strreset_inseq - request_seq - 1` can only be 0 or 1, which fits safely in a u16 and is within the 2-element `strreset_result` array. No counterexample can be constructed that passes all guards yet produces an out-of-bounds index.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 872
Taint snippeti = asoc->strreset_inseq - request_seq - 1;
Tainted vari
Truncationline 872: 32 → 16-bit u16
Sink snippeti = asoc->strreset_inseq - request_seq - 1;
Possibly guardedno
Dismissed: The combined guards at lines 867-870 and 871 constrain request_seq to [strreset_inseq-2, strreset_inseq-1], so the difference strreset_inseq - request_seq - 1 is always 0 or 1. Truncation from 32-bit to u16 is completely safe. No counterexample exists where a value passes all guards and the truncation would produce a different result.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 866
Taint snippetrequest_seq = ntohl(addstrm->request_seq);
Tainted vari
Subscript[] line 873
Sink snippetresult = asoc->strreset_result[i];
Possibly guardedno
Dismissed: strreset_result is a 2-element array. The sequence-number guards guarantee i is 0 or 1. No counterexample can pass all guards and produce i >= 2. The scanner missed that TSN_lt-based checks on request_seq bound the arithmetic difference to at most 2.

sctp_process_strreset_addstrm_out() — net/sctp/stream.c FP confidence=high

The TSN sequence number guards at lines 795-803 collectively constrain the subtraction (asoc->strreset_inseq - request_seq) to exactly 1 or 2 before line 800 is reached, making i equal to 0 or 1. Since strreset_result[] has exactly 2 elements (indices 0 and 1), both the truncation and the array subscript findings are false positives. No counterexample can be constructed because the guards are tight enough to exclude all dangerous values.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 800
Taint snippeti = asoc->strreset_inseq - request_seq - 1;
Tainted vari
Truncationline 800: 32 → 16-bit u16
Sink snippeti = asoc->strreset_inseq - request_seq - 1;
Possibly guardedno
Dismissed: The TSN guards at lines 795-796 and 799 restrict the code path to cases where request_seq is either strreset_inseq-1 or strreset_inseq-2, so the RHS of the assignment is 0 or 1. Truncation from u32 to u16 is harmless here. No counterexample can be constructed.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 794
Taint snippetrequest_seq = ntohl(addstrm->request_seq);
Tainted vari
Subscript[] line 801
Sink snippetresult = asoc->strreset_result[i];
Possibly guardedno
Dismissed: The combined TSN guards ensure i is 0 or 1 before strreset_result[i] is accessed. The strreset_result array has exactly 2 elements, so this access is always in-bounds. No counterexample can be constructed.

sctp_process_strreset_inreq() — net/sctp/stream.c FP confidence=high

The function has layered validation: (1) request_seq is bounded by TSN sequence checks so i∈{0,1} before array access; (2) nums is bounded by SCTP_MAX_CHUNK_LEN check; (3) each str_p[i] is validated against stream->outcnt in the first loop before any state writes; (4) the second loop at 668 uses stream->outcnt which is a local kernel value. All flagged sinks are adequately protected.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 625
Taint snippeti = asoc->strreset_inseq - request_seq - 1;
Tainted vari
Truncationline 625: 32 → 16-bit u16
Sink snippeti = asoc->strreset_inseq - request_seq - 1;
Possibly guardedno
Dismissed: The TSN_lt checks at lines 620-621 constrain request_seq to [strreset_inseq-2, strreset_inseq-1], making i∈{0,1}. strreset_result[] has exactly 2 entries. No counterexample can be constructed where i≥2 passes the guards.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 619
Taint snippetrequest_seq = ntohl(inreq->request_seq);
Tainted vari
Subscript[] line 626
Sink snippetresult = asoc->strreset_result[i];
Possibly guardedno
Dismissed: Same as finding #1: TSN_lt guards ensure i∈{0,1} before strreset_result[i] access. The array has 2 slots. Properly bounded.

Finding #3 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 619
Taint snippetrequest_seq = ntohl(inreq->request_seq);
Tainted vari
Loopfor_loop line 646
Sink snippetfor (i = 0; i < nums; i++) {
Possibly guardedno
Dismissed: nums is bounded by the check at line 643-645 against SCTP_MAX_CHUNK_LEN. The loop at 646 accesses str_p[i] which is within the received parameter buffer since nums was derived from param.p->length. The scanner incorrectly traces taint through request_seq to i; the actual loop variable is i used as index into str_p, not as a value derived from request_seq.

Finding #4 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 619
Taint snippetrequest_seq = ntohl(inreq->request_seq);
Tainted vari
Subscript[] line 647
Sink snippetif (ntohs(str_p[i]) >= stream->outcnt) {
Possibly guardedno
Dismissed: str_p[i] accesses are within buffer bounds because nums is derived from param.p->length and bounded by the SCTP_MAX_CHUNK_LEN check. ntohs(str_p[i]) is then checked against stream->outcnt, preventing OOB stream access.

Finding #5 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 619
Taint snippetrequest_seq = ntohl(inreq->request_seq);
Tainted vari
Loopfor_loop line 664
Sink snippetfor (i = 0; i < nums; i++)
Possibly guardedyes (heuristic)
Dismissed: Loop at line 664 uses nums with str_p[i]. Prior to this loop, the loop at 646-651 performed a full traversal validating every str_p[i] < stream->outcnt and returning early on any invalid value. This constitutes form (c) protection — prior full-traversal validation.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 619
Taint snippetrequest_seq = ntohl(inreq->request_seq);
Tainted vari
Pointer derefi->state line 665
Sink snippetSCTP_SO(stream, ntohs(str_p[i]))->state =
Possibly guardedyes (heuristic)
Dismissed: SCTP_SO(stream, ntohs(str_p[i])) uses values already validated in the loop at 646-651 to be < stream->outcnt. The state write is safe within stream->out array bounds.

Finding #7 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 619
Taint snippetrequest_seq = ntohl(inreq->request_seq);
Tainted vari
Subscript[] line 665
Sink snippetSCTP_SO(stream, ntohs(str_p[i]))->state =
Possibly guardedyes (heuristic)
Dismissed: Same as finding #6 — str_p[i] values were validated against stream->outcnt before this point.

Finding #8 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 619
Taint snippetrequest_seq = ntohl(inreq->request_seq);
Tainted vari
Loopfor_loop line 668
Sink snippetfor (i = 0; i < stream->outcnt; i++)
Possibly guardedyes (heuristic)
Dismissed: Loop at line 668 uses stream->outcnt as bound and i as index — both are local kernel values, not server-supplied. stream->outcnt controls the size of stream->out. The scanner incorrectly traces taint from request_seq to this loop's bound.

Finding #9 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 619
Taint snippetrequest_seq = ntohl(inreq->request_seq);
Tainted vari
Pointer derefi->state line 669
Sink snippetSCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
Possibly guardedyes (heuristic)
Dismissed: SCTP_SO(stream, i) where i < stream->outcnt is safe by loop invariant. stream->outcnt is a kernel-managed value, not server-supplied.

Finding #10 — Category F — cross-function via sctp_stream_outq_is_empty() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 641
Taint snippetnums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
Tainted varnums
Call siteline 653 — passes nums to sctp_stream_outq_is_empty()
Call snippetif (!sctp_stream_outq_is_empty(stream, nums, str_p)) {
Loopfor_loop line 254
Sink snippetfor (i = 0; i < str_nums; i++) {
Possibly guardedyes (heuristic)
Dismissed: sctp_stream_outq_is_empty iterates str_list[i] for i<str_nums. nums is bounded by SCTP_MAX_CHUNK_LEN check (line 643-645), and the str_p buffer has at least nums elements since nums was derived from param.p->length. The loop inside sctp_stream_outq_is_empty only reads from str_list which was validated to be within the packet buffer. No OOB access possible.

sctp_process_strreset_outreq() — net/sctp/stream.c MIXED confidence=medium

The function processes server-supplied SCTP stream reset parameters. Most findings are false positives: the i=0/1 truncation at line 542 is bounded by TSN guards; the second loop at 589 is protected by the first loop's per-element validation; the cross-function findings in sctp_ulpevent_make_stream_reset_event are false positives because the allocation is sized to accommodate stream_num elements. The main genuine concern is whether nums at line 555 is bounded against the actual received parameter buffer length before str_p[] is accessed in the first loop — SCTP's param dispatch should enforce this, but it depends on upper-layer validation not shown here.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 542
Taint snippeti = asoc->strreset_inseq - request_seq - 1;
Tainted vari
Truncationline 542: 32 → 16-bit u16
Sink snippeti = asoc->strreset_inseq - request_seq - 1;
Possibly guardedno
Dismissed: i = strreset_inseq - request_seq - 1. The guard at lines 537-541 ensures request_seq is in [strreset_inseq-2, strreset_inseq-1], so i is either 0 or 1 after truncation to u16. No counterexample possible: the guards are tight enough that the 32-to-16 truncation cannot produce an unexpected value.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 529
Taint snippetrequest_seq = ntohl(outreq->request_seq);
Tainted vari
Subscript[] line 543
Sink snippetresult = asoc->strreset_result[i];
Possibly guardedno
Dismissed: asoc->strreset_result[i] where i is 0 or 1 (proven by TSN guards). strreset_result is an array of size 2, so both indices are valid. No counterexample: i cannot exceed 1 given the guards.

Finding #3 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 529
Taint snippetrequest_seq = ntohl(outreq->request_seq);
Tainted vari
Loopfor_loop line 557
Sink snippetfor (i = 0; i < nums; i++) {
Possibly guardedno
Dismissed: nums is derived from ntohs(param.p->length). SCTP's upper-layer param dispatch validates that param.p->length does not exceed the received chunk buffer before calling this function, so str_p[i] accesses within nums elements remain within the packet buffer. This is protected by the SCTP parameter length validation in the dispatch path. Marking as false positive pending confirmation of upper-layer validation.

Finding #4 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 529
Taint snippetrequest_seq = ntohl(outreq->request_seq);
Tainted vari
Subscript[] line 558
Sink snippetif (ntohs(str_p[i]) >= stream->incnt) {
Possibly guardedno
Dismissed: str_p[i] where i < nums, and nums is computed from the param length field. SCTP validates param lengths at dispatch; the loop body checks ntohs(str_p[i]) >= stream->incnt to validate stream IDs. Access to str_p[i] within the param buffer should be safe if upper-layer length validation is done. The per-element check validates stream IDs are in range.

Finding #5 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 529
Taint snippetrequest_seq = ntohl(outreq->request_seq);
Tainted vari
Loopfor_loop line 589
Sink snippetfor (i = 0; i < nums; i++)
Possibly guardedyes (heuristic)
Dismissed: The loop at line 589 is protected by the prior full-traversal loop at lines 557-562. That loop validated every str_p[i] (same i range, same nums bound) checking each stream ID against stream->incnt. If any ID was out of range, the function jumped to 'out' before reaching line 589. So at line 589, all stream IDs in str_p[0..nums-1] are known to be < stream->incnt. SCTP_SI indexing is safe.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 529
Taint snippetrequest_seq = ntohl(outreq->request_seq);
Tainted vari
Pointer derefi->mid line 590
Sink snippetSCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
Possibly guardedyes (heuristic)
Dismissed: SCTP_SI(stream, ntohs(str_p[i])) where ntohs(str_p[i]) < stream->incnt is guaranteed by the prior validation loop. The mid field access is within valid stream array bounds. False positive.

Finding #7 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 529
Taint snippetrequest_seq = ntohl(outreq->request_seq);
Tainted vari
Subscript[] line 590
Sink snippetSCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
Possibly guardedyes (heuristic)
Dismissed: Same as finding #6: prior loop validated all stream IDs against stream->incnt. The subscript ntohs(str_p[i]) is proven < stream->incnt for all i in [0, nums). False positive.

Finding #8 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 529
Taint snippetrequest_seq = ntohl(outreq->request_seq);
Tainted vari
Loopfor_loop line 592
Sink snippetfor (i = 0; i < stream->incnt; i++)
Possibly guardedyes (heuristic)
Dismissed: This loop uses stream->incnt as the bound, not a server-supplied value. stream->incnt is a kernel-internal association parameter, not server-controlled in this context. The loop iterates over all inbound streams which the kernel itself allocated. False positive due to taint propagation confusion.

Finding #9 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 529
Taint snippetrequest_seq = ntohl(outreq->request_seq);
Tainted vari
Pointer derefi->mid line 593
Sink snippetSCTP_SI(stream, i)->mid = 0;
Possibly guardedyes (heuristic)
Dismissed: SCTP_SI(stream, i) where i < stream->incnt (loop bound). stream->incnt is a kernel-internal value representing the allocated stream array size. Accessing stream index i < incnt is safe by construction. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 555
Taint snippetnums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
Tainted varnums
Call siteline 597 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc,
Pointer derefnums-> line 905
Sink snippetsreset->strreset_type = SCTP_STREAM_RESET_EVENT;
Possibly guardedno
Dismissed: sreset is obtained from skb_put(skb, length) where length = sizeof(struct sctp_stream_reset_event) + 2*stream_num. The struct fields being accessed (strreset_type, strreset_flags, etc.) are within the fixed-size prefix of the struct, well within the allocated length. The taint propagation is spurious — nums affects length which determines the skb allocation, but the fixed struct fields are always within bounds. False positive.

Finding #11 — Category E — cross-function via sctp_ulpevent_make_stream_reset_event() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 555
Taint snippetnums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
Tainted varnums
Call siteline 597 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc,
Pointer derefnums-> line 906
Sink snippetsreset->strreset_flags = flags;
Possibly guardedno
Dismissed: Same as #10. sreset->strreset_flags is a fixed field in the struct, within the skb_put allocation. False positive from taint propagation.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 555
Taint snippetnums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
Tainted varnums
Call siteline 597 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc,
Pointer derefnums-> line 907
Sink snippetsreset->strreset_length = length;
Possibly guardedno
Dismissed: Same as #10. sreset->strreset_length is within the fixed struct prefix, always within the skb_put allocation. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 555
Taint snippetnums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
Tainted varnums
Call siteline 597 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc,
Pointer derefnums-> line 909
Sink snippetsreset->strreset_assoc_id = sctp_assoc2id(asoc);
Possibly guardedno
Dismissed: Same as #10. sreset->strreset_assoc_id is within the fixed struct prefix. False positive.

Finding #14 — Category F — cross-function via sctp_ulpevent_make_stream_reset_event() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 555
Taint snippetnums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
Tainted varnums
Call siteline 597 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc,
Loopfor_loop line 911
Sink snippetfor (i = 0; i < stream_num; i++)
Possibly guardedno
Dismissed: The loop in sctp_ulpevent_make_stream_reset_event iterates stream_num times writing to sreset->strreset_stream_list[i]. The skb allocation is length = sizeof(struct) + 2*stream_num bytes, and strreset_stream_list is a flexible array at the end of the struct. The loop writes exactly 2*stream_num bytes into the allocated space — no OOB. stream_num (__u16) is at most 32767, so 2*stream_num fits in int. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 555
Taint snippetnums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
Tainted varnums
Call siteline 597 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc,
Pointer derefnums-> line 912
Sink snippetsreset->strreset_stream_list[i] = ntohs(stream_list[i]);
Possibly guardedno
Dismissed: sreset->strreset_stream_list[i] for i < stream_num, within the skb_put allocated region of size sizeof(struct) + 2*stream_num. Access is within bounds by construction of the allocation. False positive.

sctp_process_strreset_resp() — net/sctp/stream.c FP confidence=high

The flagged values (outreq->param_hdr.length, addstrm->number_of_streams) come from locally-built kernel request structs stored in asoc->strreset_chunk, not from server-supplied response data. The resp (server-supplied) is only used for result/response_seq. The req pointer retrieved via sctp_chunk_lookup_strreset_param points to the kernel's own previously-sent request chunk. All tainted values are internally controlled, making all findings false positives.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 951
Taint snippetnums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
Tainted varnums
Loopfor_loop line 957
Sink snippetfor (i = 0; i < nums; i++) {
Possibly guardedno
Dismissed: outreq is cast from req, which was retrieved from asoc->strreset_chunk — a locally-built kernel request, not a server response. nums derived from outreq->param_hdr.length is kernel-controlled. str_p points into the locally-built request. No server-supplied data controls this loop.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 1049
Taint snippetnums = ntohs(addstrm->number_of_streams);
Tainted vari
Pointer derefi->state line 1054
Sink snippetSCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
Possibly guardedno
Dismissed: addstrm is cast from req retrieved from asoc->strreset_chunk — a locally-built kernel request. addstrm->number_of_streams was set by the kernel when building the ADD_OUT_STREAMS request. SCTP_SO(stream, i) uses loop variable i bounded by stream->outcnt, not by nums directly.

Finding #3 — Category E — cross-function via sctp_ulpevent_make_stream_reset_event() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 951
Taint snippetnums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
Tainted varnums
Call siteline 976 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
Pointer derefnums-> line 905
Sink snippetsreset->strreset_type = SCTP_STREAM_RESET_EVENT;
Possibly guardedno
Dismissed: nums is from locally-built outreq. In sctp_ulpevent_make_stream_reset_event(), sreset is allocated via skb_put with length = sizeof(sctp_stream_reset_event) + 2*stream_num, so sreset access at line 905 is within the newly allocated buffer. False positive — scanner misidentifies the taint source and the allocation pattern.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 951
Taint snippetnums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
Tainted varnums
Call siteline 976 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
Pointer derefnums-> line 906
Sink snippetsreset->strreset_flags = flags;
Possibly guardedno
Dismissed: Same as finding #3. sreset->strreset_flags write at line 906 is within the skb_put-allocated buffer sized to accommodate stream_num. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 951
Taint snippetnums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
Tainted varnums
Call siteline 976 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
Pointer derefnums-> line 907
Sink snippetsreset->strreset_length = length;
Possibly guardedno
Dismissed: Same as finding #3. sreset->strreset_length write at line 907 is within the skb_put-allocated buffer. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 951
Taint snippetnums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
Tainted varnums
Call siteline 976 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
Pointer derefnums-> line 909
Sink snippetsreset->strreset_assoc_id = sctp_assoc2id(asoc);
Possibly guardedno
Dismissed: Same as finding #3. sreset->strreset_assoc_id write at line 909 is within the skb_put-allocated buffer. False positive.

Finding #7 — Category F — cross-function via sctp_ulpevent_make_stream_reset_event() — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 951
Taint snippetnums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
Tainted varnums
Call siteline 976 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
Loopfor_loop line 911
Sink snippetfor (i = 0; i < stream_num; i++)
Possibly guardedno
Dismissed: nums is locally controlled (from kernel-built outreq). The loop in sctp_ulpevent_make_stream_reset_event() at line 911 iterates over stream_list (locally-built str_p) with stream_num (locally-derived nums) as bound. The sreset->strreset_stream_list array is sized to 2*stream_num in the allocation. False positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 951
Taint snippetnums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) /
Tainted varnums
Call siteline 976 — passes nums to sctp_ulpevent_make_stream_reset_event()
Call snippet*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
Pointer derefnums-> line 912
Sink snippetsreset->strreset_stream_list[i] = ntohs(stream_list[i]);
Possibly guardedno
Dismissed: Same as finding #7. sreset->strreset_stream_list[i] access is within the skb_put buffer sized for stream_num entries. stream_list[i] reads from locally-built str_p. False positive.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1049
Taint snippetnums = ntohs(addstrm->number_of_streams);
Tainted varnumber
Call siteline 1058 — passes number to sctp_stream_outq_migrate()
Call snippetsctp_stream_outq_migrate(stream, NULL, number);
Loopfor_loop line 85
Sink snippetfor (i = 0; i < outcnt; i++) {
Possibly guardedno
Dismissed: addstrm->number_of_streams is from a locally-built kernel request. number = stream->outcnt - nums is a kernel-computed value. sctp_stream_outq_migrate() with outcnt=number only accesses stream->out entries up to min(stream->outcnt, outcnt). False positive.

sctp_process_strreset_tsnreq() — net/sctp/stream.c FP confidence=high

The scanner propagates taint from 'request_seq' (server-supplied) to 'i' at line 704, then incorrectly continues propagating that taint to uses of 'i' in the loops at lines 764-769. However, 'i' is a reused local variable — in the loops, it is initialized to 0 and incremented as a plain counter bounded by kernel-internal values (stream->outcnt, stream->incnt), not by any server-supplied value. Findings #1 and #2 relate to line 704-705 where i is indeed derived from server data, but the sequence number guards at lines 699-703 mathematically constrain i to {0, 1}, matching the 2-element strreset_result array. All findings are false positives.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcentohl() line 704
Taint snippeti = asoc->strreset_inseq - request_seq - 1;
Tainted vari
Truncationline 704: 32 → 16-bit u16
Sink snippeti = asoc->strreset_inseq - request_seq - 1;
Possibly guardedno
Dismissed: The guards at lines 699-703 ensure request_seq is within [strreset_inseq-2, strreset_inseq-1], so i = strreset_inseq - request_seq - 1 is in {0, 1}. No counterexample: any value of request_seq passing both guards yields i in {0,1}, within the 2-element array. The truncation from 32-bit to 16-bit is also safe since the value is at most 1.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 698
Taint snippetrequest_seq = ntohl(tsnreq->request_seq);
Tainted vari
Subscript[] line 705
Sink snippetresult = asoc->strreset_result[i];
Possibly guardedno
Dismissed: Same analysis as #1. The guards mathematically constrain i to {0,1}. strreset_result[] has 2 elements indexed by 0 and 1. No out-of-bounds access is possible.

Finding #3 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 698
Taint snippetrequest_seq = ntohl(tsnreq->request_seq);
Tainted vari
Loopfor_loop line 764
Sink snippetfor (i = 0; i < stream->outcnt; i++) {
Possibly guardedno
Dismissed: False positive due to taint variable name reuse. In the loop at line 764, 'i' is a fresh loop counter starting at 0, bounded by stream->outcnt which is a kernel-internal property of the association, not derived from server-supplied request_seq. The scanner incorrectly propagated taint from the earlier use of 'i' at line 704.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 698
Taint snippetrequest_seq = ntohl(tsnreq->request_seq);
Tainted vari
Pointer derefi->mid line 765
Sink snippetSCTP_SO(stream, i)->mid = 0;
Possibly guardedno
Dismissed: Same as #3. SCTP_SO(stream, i) uses loop counter i in [0, stream->outcnt), which is a kernel-maintained value. Not server-controlled. False positive.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 698
Taint snippetrequest_seq = ntohl(tsnreq->request_seq);
Tainted vari
Pointer derefi->mid_uo line 766
Sink snippetSCTP_SO(stream, i)->mid_uo = 0;
Possibly guardedno
Dismissed: Same as #3 and #4. mid_uo field write is on stream->out[i] where i is a loop counter bounded by kernel-internal outcnt. False positive.

Finding #6 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 698
Taint snippetrequest_seq = ntohl(tsnreq->request_seq);
Tainted vari
Loopfor_loop line 768
Sink snippetfor (i = 0; i < stream->incnt; i++)
Possibly guardedno
Dismissed: Same reasoning as #3. The loop at line 768 uses i as a fresh counter from 0 to stream->incnt (kernel-internal). Not server-derived. False positive.

Finding #7 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohl() line 698
Taint snippetrequest_seq = ntohl(tsnreq->request_seq);
Tainted vari
Pointer derefi->mid line 769
Sink snippetSCTP_SI(stream, i)->mid = 0;
Possibly guardedno
Dismissed: Same as #6. SCTP_SI(stream, i) uses loop counter bounded by kernel-internal incnt. False positive.

smc_clc_msg_hdr_valid() — net/smc/smc_clc.c FP confidence=medium

The trl pointer is derived from server-supplied ntohs(hdr.length), but two layers of protection exist: (1) the call site in smc_clc_wait_msg() sets check_trl=false when datlen>buflen, ensuring trl computation only happens when hdr.length<=buflen; (2) smc_clc_msg_acc_conf_valid() is called before trl is computed and (by analogy with smc_clc_msg_decl_valid) validates hdr.length against known struct sizes, preventing underflow. The analysis is medium-confidence because smc_clc_msg_acc_conf_valid source is not provided.

Finding #1 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohs() line 492
Taint snippettrl = (struct smc_clc_msg_trail *)
Tainted vartrl
Sinkmemcmp() line 505 (arg 0, role=pointer)
Sink snippetmemcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
Possibly guardedno
Dismissed: smc_clc_msg_acc_conf_valid() validates hdr.length before trl is computed; call site ensures datlen<=buflen when check_trl=true. No counterexample possible if acc_conf_valid checks minimum length.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 492
Taint snippettrl = (struct smc_clc_msg_trail *)
Tainted vartrl
Pointer dereftrl->eyecatcher line 505
Sink snippetmemcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
Possibly guardedno
Dismissed: Same reasoning as finding #1 — trl dereference is protected by upstream validator and call-site datlen<=buflen guard.

Finding #3 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcentohs() line 492
Taint snippettrl = (struct smc_clc_msg_trail *)
Tainted vartrl
Sinkmemcmp() line 506 (arg 0, role=pointer)
Sink snippetmemcmp(trl->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
Possibly guardedno
Dismissed: Same reasoning as finding #1 — second memcmp on line 506 is guarded by the same validation chain.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcentohs() line 492
Taint snippettrl = (struct smc_clc_msg_trail *)
Tainted vartrl
Pointer dereftrl->eyecatcher line 506
Sink snippetmemcmp(trl->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
Possibly guardedno
Dismissed: Same reasoning as finding #2 — second trl->eyecatcher dereference on line 506 is covered by the same validation chain.

smc_rtoken_set() — net/smc/smc_core.c FP confidence=high

The static analyzer propagates taint from ntohl(nw_rkey_known) through the return value of smc_rtoken_find_by_link(). However, that function uses the network-supplied key only as a search key; its return value is a local loop index i in [0, SMC_RMBS_PER_LGR_MAX), or -ENOENT. The -ENOENT case is explicitly handled with an early return, so rtok_idx at the sink is always in [0, SMC_RMBS_PER_LGR_MAX). No counterexample can be constructed. Both findings are false positives.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 2642
Taint snippetrtok_idx = smc_rtoken_find_by_link(lgr, link_idx, ntohl(nw_rkey_known));
Tainted varrtok_idx
Subscript[] line 2645
Sink snippetlgr->rtokens[rtok_idx][link_idx_new].rkey = ntohl(nw_rkey);
Possibly guardedyes (heuristic)
Dismissed: rtok_idx is not the server-supplied value itself but the loop index from smc_rtoken_find_by_link(), bounded to [0, SMC_RMBS_PER_LGR_MAX). The == -ENOENT check handles the only error path. Could not construct a counterexample — the bounds are tight.

Finding #2 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 2642
Taint snippetrtok_idx = smc_rtoken_find_by_link(lgr, link_idx, ntohl(nw_rkey_known));
Tainted varrtok_idx
Subscript[] line 2646
Sink snippetlgr->rtokens[rtok_idx][link_idx_new].dma_addr = be64_to_cpu(nw_vaddr);
Possibly guardedyes (heuristic)
Dismissed: Same reasoning as finding #1. rtok_idx is a loop-bounded internal index, not a direct alias of the network-supplied rkey. The guard is sufficient; no counterexample exists.

put_user_ifreq() — net/socket.c FP confidence=high

The 'size' variable in put_user_ifreq() is entirely kernel-controlled. It is initialised to sizeof(struct ifreq) and can only be changed to sizeof(struct compat_ifreq) based on the kernel's own in_compat_syscall() check. Neither value is user-supplied or server-supplied — both are compile-time constants determined by the kernel ABI. The source buffer 'ifr' is a kernel pointer passed in by the caller. The copy_to_user() destination 'arg' is user-space, but the size argument is not user-controlled in any way. The scanner's taint chain appears to be a false positive arising from treating the return value or arguments of copy_to_user() itself as tainted, which is incorrect here.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 3459
Taint snippetif (copy_to_user(arg, ifr, size))
Tainted varsize
Unvalidated sizecopy_to_user() arg 2 line 3459 — size size
Sink snippetif (copy_to_user(arg, ifr, size))
Possibly guardedno
Dismissed: The 'size' variable is set exclusively from sizeof() expressions on kernel-defined struct types (struct ifreq or struct compat_ifreq), controlled by in_compat_syscall(). These are compile-time constants — not user-supplied or server-supplied values. No counterexample can be constructed because the value of 'size' cannot be influenced by user input. This is a clear false positive from the static analyser treating the size in copy_to_user() as tainted without tracking that it originates from kernel-internal sizeof() computations.

rpc_pipe_generic_upcall() — net/sunrpc/rpc_pipe.c FP confidence=high

The scanner misidentifies the taint source and sink. 'mlen' is computed as min(msg->len - msg->copied, buflen), where buflen is the kernel-supplied destination buffer length passed in by the VFS read path. The copy_to_user call uses mlen as the size, which is already bounded by both the message's remaining data (msg->len - msg->copied) and the caller-supplied buflen. The 'taint source' the scanner cites is the return value of copy_to_user (the number of bytes NOT copied), which is then used to adjust mlen downward — this is standard copy_to_user residue handling, not a dangerous size derived from user or server input. There is no OOB risk here.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 111
Taint snippetleft = copy_to_user(dst, data, mlen);
Tainted varmlen
Unvalidated sizecopy_to_user() arg 2 line 111 — size mlen
Sink snippetleft = copy_to_user(dst, data, mlen);
Possibly guardedno
Dismissed: The scanner incorrectly treats the return value of copy_to_user() (the 'left' residue count) as a taint source and then flags the same copy_to_user() call as both source and sink. In reality, mlen = min(msg->len - msg->copied, buflen) is bounded above by both the message's remaining length and the caller-provided buffer length. The subsequent 'left = copy_to_user(dst, data, mlen)' is entirely safe. The 'mlen -= left' line adjusts for bytes not transferred, and the result is used only to update msg->copied and the return value — no second copy occurs. No counterexample can be constructed where mlen exceeds buflen, because min() enforces that invariant. This is a false positive.
The depth value is server-supplied (from ntohl of a network field) but is explicitly clamped to a maximum of 4 before the loop. The header array has exactly 4 elements (indices 0-3). With depth clamped to [0,4] and the loop running for i in [0, depth), the maximum index accessed is 3, which is always within bounds. No counterexample can be constructed: any depth value from ntohl() that exceeds 4 is reduced to exactly 4, and the loop accesses header[0] through header[3] at most — all valid indices into the 4-element array.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 884
Taint snippetdepth = ntohl(ntq->depth);
Tainted vardepth
Loopfor_loop line 888
Sink snippetfor (i = 0; i < depth; i++)
Possibly guardedno
Dismissed: The guard 'if (depth > 4) depth = 4;' at line 886-887 clamps the loop bound to exactly the size of the header array (4 elements). No counterexample exists: depth is always in [0,4] before the loop, so i is always in [0,3], and header[i] is always a valid access. The scanner's 'possibly guarded: no' flag appears to have missed this explicit clamp. This is a false positive.

tipc_rcv() — net/tipc/node.c FP confidence=high

tipc_rcv() has solid validation discipline: tipc_msg_validate() is called before header field access, node lookup failures are checked, and bearer_id is derived from a local struct field. The flagged finding misidentifies tipc_node_find() as a dangerous sink when it is actually a lookup function that bounds its hash subscript via power-of-2 masking (tipc_hashfn uses & (NODE_HTABLE_SIZE-1)), making OOB array access impossible regardless of the input value.

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

CategoryCat C — server value → array subscript
Taint sourcentohl() line 2105
Taint snippetn = tipc_node_find(net, ntohl(ehdr->addr));
Tainted varntohl(ehdr->addr)
Call siteline 2105 — passes ntohl(ehdr->addr) to tipc_node_find()
Call snippetn = tipc_node_find(net, ntohl(ehdr->addr));
Subscript (in callee)[] line 337
Sink snippethlist_for_each_entry_rcu(node, &tn->node_htable[thash], hash) {
Possibly guardedno
Dismissed: tipc_node_find() is a hash-table lookup function, not a vulnerable sink. tipc_hashfn() computes addr & (NODE_HTABLE_SIZE-1), bounding the subscript to [0, NODE_HTABLE_SIZE-1] regardless of the 32-bit input value. No counterexample exists: for any 32-bit ntohl(ehdr->addr), the AND mask guarantees the subscript stays within the statically-allocated node_htable array. The scanner flagged the hash table dereference inside the lookup helper without accounting for the masking arithmetic.

virtio_transport_build_skb() — net/vmw_vsock/virtio_transport_common.c FP confidence=high

The scanner incorrectly propagated taint from payload_len (le32_to_cpu result) to hdr. The hdr pointer is obtained via skb_put(skb, sizeof(*hdr)) on a freshly kernel-allocated skb, not via any offset arithmetic using payload_len. The only legitimate concern would be a potential integer overflow in the alloc_skb size argument (sizeof(*hdr) + sizeof(*pkt_hdr) + payload_len) if payload_len is very large, but that is not what was flagged. All flagged accesses through hdr are into locally-allocated memory of exactly sizeof(*hdr) bytes, making all findings false positives.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->src_cid line 142
Sink snippethdr->src_cid = pkt_hdr->src_cid;
Possibly guardedno
Dismissed: hdr is from skb_put(skb, sizeof(*hdr)) on a newly allocated skb, not derived from payload_len. The taint on payload_len does not propagate to hdr's base address. False positive due to incorrect taint propagation through alloc_skb/skb_put.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->src_port line 143
Sink snippethdr->src_port = pkt_hdr->src_port;
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->dst_cid line 144
Sink snippethdr->dst_cid = pkt_hdr->dst_cid;
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->dst_port line 145
Sink snippethdr->dst_port = pkt_hdr->dst_port;
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->transport line 147
Sink snippethdr->transport = cpu_to_le16(AF_VSOCK_TRANSPORT_VIRTIO);
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->len line 148
Sink snippethdr->len = cpu_to_le16(sizeof(*pkt_hdr));
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #7 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Sinkmemset() line 149 (arg 2, role=size)
Sink snippetmemset(hdr->reserved, 0, sizeof(hdr->reserved));
Possibly guardedno
Dismissed: The size argument to memset is sizeof(hdr->reserved), a compile-time constant, not payload_len. The destination hdr->reserved is within the locally-allocated hdr struct. False positive.

Finding #8 — Category A — false positive

CategoryCat A — server offset → pointer → memory op
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Sinkmemset() line 149 (arg 0, role=pointer)
Sink snippetmemset(hdr->reserved, 0, sizeof(hdr->reserved));
Possibly guardedno
Dismissed: hdr->reserved is a field within the locally-allocated af_vsockmon_hdr struct. No server-supplied offset arithmetic involved in deriving this pointer.

Finding #9 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->reserved line 149
Sink snippetmemset(hdr->reserved, 0, sizeof(hdr->reserved));
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #10 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->op line 154
Sink snippethdr->op = cpu_to_le16(AF_VSOCK_OP_CONNECT);
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #11 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->op line 158
Sink snippethdr->op = cpu_to_le16(AF_VSOCK_OP_DISCONNECT);
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #12 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->op line 161
Sink snippethdr->op = cpu_to_le16(AF_VSOCK_OP_PAYLOAD);
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #13 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->op line 165
Sink snippethdr->op = cpu_to_le16(AF_VSOCK_OP_CONTROL);
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

Finding #14 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcele32_to_cpu() line 132
Taint snippetpayload_len = le32_to_cpu(pkt_hdr->len);
Tainted varhdr
Pointer derefhdr->op line 168
Sink snippethdr->op = cpu_to_le16(AF_VSOCK_OP_UNKNOWN);
Possibly guardedno
Dismissed: Same as #1: hdr is a locally-allocated pointer, not derived from server-supplied offset arithmetic.

nl80211_send_iftype_data() — net/wireless/nl80211.c FP confidence=high

The data in question (eht_cap->eht_ppe_thres) comes from driver-registered ieee80211_sband_iftype_data structures, which represent the LOCAL device's own capabilities set by the kernel wireless driver at registration time — not from network packets or server responses. The get_unaligned_le16() call is on locally-initialized driver data. Additionally, ieee80211_eht_ppe_size() itself returns u8, meaning it already constrains the output to 8 bits before assignment to ppe_thresh_size.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourceget_unaligned_le16() line 2189
Taint snippetppe_thresh_size =
Tainted varppe_thresh_size
Truncationline 2189: 16 → 8-bit u8
Sink snippetppe_thresh_size =
Possibly guardedno
Dismissed: The eht_cap data originates from struct ieee80211_sband_iftype_data registered by the local wireless driver (sband->iftype_data), not from any remote server or network packet. get_unaligned_le16() is being called on locally-initialized driver capability data. Furthermore, ieee80211_eht_ppe_size() is declared to return u8, so its result is already bounded to 8 bits before the assignment to ppe_thresh_size. No counterexample is possible because the function return type itself prevents values > 255. This is a false positive: the scanner incorrectly treated driver-registered capability data as server-supplied, and the taint path through a u8-returning function is inherently bounded.

__regdb_query_wmm() — net/wireless/reg.c BUG confidence=high

The function reads from a firmware-supplied binary blob (regdb) and uses embedded offsets (coll_ptr, rules_ptr entries) to compute struct pointers without any bounds validation against the known firmware buffer size. Both coll and rule pointers are derived from firmware-controlled offset arithmetic with no check that offset+sizeof(*struct) <= db_size before dereferencing. The cross-function findings in set_wmm_rule are likely false positives because valid_wmm() is called before the flagged accesses.

Finding #1 — Category F — BUG oob_read

CategoryCat F — server value → loop iteration count
Taint sourcebe16_to_cpu() line 871
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Loopfor_loop line 875
Sink snippetfor (i = 0; i < coll->n_rules; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in __regdb_query_wmm when firmware blob contains a crafted coll_ptr yielding n_rules that causes the loop to iterate beyond the buffer
Fix: Validate that ptr + sizeof(struct fwdb_collection) <= db_size before forming coll pointer. Additionally validate coll->n_rules such that the entire rules array fits within the buffer.
CVE pattern: Firmware blob offset OOB — similar pattern to CVE-2019-17666 style firmware parsing bugs

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 871
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->n_rules line 875
Sink snippetfor (i = 0; i < coll->n_rules; i++) {
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in __regdb_query_wmm reading coll->n_rules from out-of-bounds firmware offset
Fix: Before casting (u8*)db + ptr to struct fwdb_collection*, verify ptr + sizeof(struct fwdb_collection) <= db_size.
CVE pattern: Firmware offset OOB read

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 871
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->len line 876
Sink snippet__be16 *rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2));
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading coll->len from unvalidated firmware offset in __regdb_query_wmm
Fix: Verify ptr + sizeof(struct fwdb_collection) <= db_size before dereferencing coll. Also validate ALIGN(coll->len, 2) + n_rules * sizeof(__be16) fits within db bounds before forming rules_ptr.
CVE pattern: Firmware offset OOB read

Finding #4 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->len line 880
Sink snippetif (rule->len < offsetofend(struct fwdb_rule, wmm_ptr))
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->len from crafted rules_ptr entry in __regdb_query_wmm
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= db_size before casting to struct fwdb_rule*. The rule->len check on line 880 is itself the dangerous dereference.
CVE pattern: Firmware offset OOB read

Finding #5 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->start line 883
Sink snippetif (freq >= KHZ_TO_MHZ(be32_to_cpu(rule->start)) &&
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->start from out-of-bounds firmware offset
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= db_size before dereferencing rule.
CVE pattern: Firmware offset OOB read

Finding #6 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->end line 884
Sink snippetfreq <= KHZ_TO_MHZ(be32_to_cpu(rule->end))) {
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->end from out-of-bounds firmware offset
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= db_size before dereferencing rule.
CVE pattern: Firmware offset OOB read

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 885 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 853
Sink snippetecw2cw((wmm->client[i].ecw & 0xf0) >> 4);
Possibly guardedyes (heuristic)
Dismissed: The actual sink accesses wmm->client[i], not rule directly. wmm is derived from rule->wmm_ptr but valid_wmm(wmm) is called at line 844 before any wmm field accesses. Assuming valid_wmm validates the wmm buffer, this is a false positive.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 885 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 854
Sink snippetwmm_rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #7 — wmm->client[i] access protected by valid_wmm() call at line 844.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 885 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 855
Sink snippetwmm_rule->client[i].aifsn = wmm->client[i].aifsn;
Possibly guardedyes (heuristic)
Dismissed: Same as finding #7 — protected by valid_wmm().

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 885 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 857
Sink snippet1000 * be16_to_cpu(wmm->client[i].cot);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #7 — protected by valid_wmm().

Finding #11 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 885 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 858
Sink snippetwmm_rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #7 — wmm->ap[i] access protected by valid_wmm().

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 885 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 859
Sink snippetwmm_rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #7 — protected by valid_wmm().

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 885 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 860
Sink snippetwmm_rule->ap[i].aifsn = wmm->ap[i].aifsn;
Possibly guardedyes (heuristic)
Dismissed: Same as finding #7 — protected by valid_wmm().

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 877
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 885 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 861
Sink snippetwmm_rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot);
Possibly guardedyes (heuristic)
Dismissed: Same as finding #7 — protected by valid_wmm().

regdb_query_country() — net/wireless/reg.c MIXED confidence=medium

The function derives 'coll' and 'rule' pointers from firmware-supplied 16-bit offset fields (shifted left by 2) with no validation that the resulting offsets + sizeof(*coll)/sizeof(*rule) fall within the firmware blob's bounds. regdom is locally kzalloc'd and findings tainting it via the line-919 source are false positives. The genuine bugs are: (1) coll pointer unvalidated against firmware size; (2) rule pointer unvalidated against firmware size; (3) coll->n_rules unvalidated before kzalloc_flex, potentially causing a massive allocation. | The function parses firmware-supplied data without validating that computed offsets (coll_ptr, rule_ptr) fall within the firmware buffer bounds. Findings about 'rrule' are false positives because rrule points into locally kzalloc'd memory (regdom->reg_rules[i]), not into the firmware buffer. Findings about 'rule' and 'coll' are genuine bugs: unvalidated firmware offsets could point outside the firmware buffer. The regulatory database is loaded from firmware files, making this an attack surface if a malicious firmware file is used. | Findings #1-4 trace taint from rule->wmm_ptr into wmm pointer, but valid_wmm(wmm) is called before the flagged sinks (lines 858-861), validating wmm before dereferencing. Findings #5-12 incorrectly treat rrule (pointer into locally-allocated regdom) as tainted; the allocation was sized to n_rules and i is bounded by n_reg_rules==n_rules, so no OOB. The real concern (unvalidated rule_ptr/coll_ptr offsets against db buffer bounds) is present but not directly what's flagged in these sinks.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->n_rules line 924
Sink snippetregdom = kzalloc_flex(*regdom, reg_rules, coll->n_rules);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds or kernel panic reading coll->n_rules from beyond firmware blob
Fix: Validate that ptr + sizeof(struct fwdb_collection) <= regdb_size before casting to struct fwdb_collection*
CVE pattern: firmware blob offset OOB — similar to CVE-2019-17133 style offset validation missing

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varregdom
Pointer derefregdom->n_reg_rules line 928
Sink snippetregdom->n_reg_rules = coll->n_rules;
Possibly guardedno
Dismissed: regdom is allocated locally by kzalloc_flex; it is not derived from server/firmware offset arithmetic. The taint propagation from be16_to_cpu line 919 to regdom is spurious — false positive.

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->n_rules line 928
Sink snippetregdom->n_reg_rules = coll->n_rules;
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading coll->n_rules from beyond firmware blob bounds
Fix: Validate ptr + sizeof(struct fwdb_collection) <= regdb_size before use
CVE pattern: firmware blob offset OOB

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varregdom
Pointer derefregdom->alpha2 line 929
Sink snippetregdom->alpha2[0] = country->alpha2[0];
Possibly guardedno
Dismissed: regdom->alpha2[0] is a write to a locally kzalloc'd struct. regdom is not derived from the be16_to_cpu offset. False positive.

Finding #5 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varregdom
Pointer derefregdom->alpha2 line 930
Sink snippetregdom->alpha2[1] = country->alpha2[1];
Possibly guardedno
Dismissed: Same as #4 — regdom->alpha2[1] write to locally-allocated struct. False positive.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varregdom
Pointer derefregdom->dfs_region line 931
Sink snippetregdom->dfs_region = coll->dfs_region;
Possibly guardedno
Dismissed: regdom->dfs_region is a field in the locally kzalloc'd regdom struct. False positive on the regdom side. The coll->dfs_region read is covered by finding #7.

Finding #7 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->dfs_region line 931
Sink snippetregdom->dfs_region = coll->dfs_region;
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading coll->dfs_region beyond firmware blob
Fix: Validate ptr + sizeof(struct fwdb_collection) <= regdb_size before dereferencing coll
CVE pattern: firmware blob offset OOB

Finding #8 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varregdom
Loopfor_loop line 933
Sink snippetfor (i = 0; i < regdom->n_reg_rules; i++) {
Possibly guardedno
Dismissed: The loop bound is regdom->n_reg_rules which was set from coll->n_rules. kzalloc_flex allocated exactly n_rules slots in regdom, so regdom->reg_rules[i] for i < n_reg_rules is within the allocated buffer. The real concern is the unvalidated coll pointer (finding #1/#3) and large n_rules causing big allocation, but the loop itself over regdom->reg_rules does not OOB the regdom allocation. False positive for this specific loop-bounds finding.

Finding #9 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varregdom
Pointer derefregdom->n_reg_rules line 933
Sink snippetfor (i = 0; i < regdom->n_reg_rules; i++) {
Possibly guardedno
Dismissed: regdom is locally allocated; reading regdom->n_reg_rules is reading from a locally-controlled struct field. False positive.

Finding #10 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->len line 934
Sink snippet__be16 *rules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2));
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading coll->len beyond firmware blob
Fix: Validate ptr + sizeof(struct fwdb_collection) <= regdb_size before dereferencing coll->len
CVE pattern: firmware blob offset OOB

Finding #11 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varregdom
Pointer derefregdom->reg_rules line 937
Sink snippetstruct ieee80211_reg_rule *rrule = &regdom->reg_rules[i];
Possibly guardedno
Dismissed: regdom->reg_rules[i] — regdom is locally kzalloc'd with n_rules entries; accessing index i < n_reg_rules is within bounds. False positive.

Finding #12 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->freq_range line 939
Sink snippetrrule->freq_range.start_freq_khz = be32_to_cpu(rule->start);
Possibly guardedno
Dismissed: rrule points into locally kzalloc'd regdom->reg_rules array; not derived from firmware offset arithmetic. False positive.

Finding #13 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->start line 939
Sink snippetrrule->freq_range.start_freq_khz = be32_to_cpu(rule->start);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds or kernel panic reading rule->start from beyond firmware blob
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= regdb_size before dereferencing rule
CVE pattern: firmware blob offset OOB

Finding #14 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->freq_range line 940
Sink snippetrrule->freq_range.end_freq_khz = be32_to_cpu(rule->end);
Possibly guardedno
Dismissed: rrule is from locally-allocated regdom; false positive for the rrule taint chain from line 919.

Finding #15 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->end line 940
Sink snippetrrule->freq_range.end_freq_khz = be32_to_cpu(rule->end);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->end from beyond firmware blob
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= regdb_size before dereferencing rule
CVE pattern: firmware blob offset OOB

Finding #16 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->freq_range line 941
Sink snippetrrule->freq_range.max_bandwidth_khz = be32_to_cpu(rule->max_bw);
Possibly guardedno
Dismissed: rrule is from locally-allocated regdom. False positive.

Finding #17 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->max_bw line 941
Sink snippetrrule->freq_range.max_bandwidth_khz = be32_to_cpu(rule->max_bw);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->max_bw from beyond firmware blob
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= regdb_size before dereferencing rule
CVE pattern: firmware blob offset OOB

Finding #18 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->power_rule line 943
Sink snippetrrule->power_rule.max_antenna_gain = 0;
Possibly guardedno
Dismissed: rrule->power_rule.max_antenna_gain = 0 is a write to locally-allocated regdom. False positive.

Finding #19 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->power_rule line 944
Sink snippetrrule->power_rule.max_eirp = be16_to_cpu(rule->max_eirp);
Possibly guardedno
Dismissed: rrule is from locally-allocated regdom. False positive.

Finding #20 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->max_eirp line 944
Sink snippetrrule->power_rule.max_eirp = be16_to_cpu(rule->max_eirp);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->max_eirp from beyond firmware blob
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= regdb_size before dereferencing rule
CVE pattern: firmware blob offset OOB

Finding #21 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->flags line 946
Sink snippetrrule->flags = 0;
Possibly guardedno
Dismissed: rrule = &regdom->reg_rules[i] where regdom is locally kzalloc'd. Writing to rrule->flags is a write to locally allocated memory, not a dereference of a firmware-offset-derived pointer. False positive: the taint tracer incorrectly propagated through n_rules to the loop index and then to regdom->reg_rules[i], but that memory is locally allocated.

Finding #22 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->flags line 947
Sink snippetif (rule->flags & FWDB_FLAG_NO_OFDM)
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds or wild pointer dereference when firmware contains a crafted rule_ptr value pointing outside the firmware buffer
Fix: Before forming 'rule = (void *)((u8 *)db + rule_ptr)', validate that rule_ptr + sizeof(struct fwdb_rule) <= firmware_size. The firmware size should be tracked (e.g., passed as a parameter or stored globally alongside regdb).
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #23 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->flags line 948
Sink snippetrrule->flags |= NL80211_RRF_NO_OFDM;
Possibly guardedno
Dismissed: Same as finding #1: rrule points to locally allocated regdom->reg_rules[i]. False positive.

Finding #24 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->flags line 949
Sink snippetif (rule->flags & FWDB_FLAG_NO_OUTDOOR)
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds or kernel crash reading rule->flags from out-of-bounds firmware offset
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= firmware_size before accessing any rule fields.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #25 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->flags line 950
Sink snippetrrule->flags |= NL80211_RRF_NO_OUTDOOR;
Possibly guardedno
Dismissed: rrule is locally allocated memory. False positive.

Finding #26 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->flags line 951
Sink snippetif (rule->flags & FWDB_FLAG_DFS)
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->flags from out-of-bounds firmware offset
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= firmware_size before dereferencing rule.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #27 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->flags line 952
Sink snippetrrule->flags |= NL80211_RRF_DFS;
Possibly guardedno
Dismissed: rrule is locally allocated memory. False positive.

Finding #28 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->flags line 953
Sink snippetif (rule->flags & FWDB_FLAG_NO_IR)
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->flags from out-of-bounds firmware offset
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= firmware_size before dereferencing rule.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #29 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->flags line 954
Sink snippetrrule->flags |= NL80211_RRF_NO_IR;
Possibly guardedno
Dismissed: rrule is locally allocated memory. False positive.

Finding #30 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->flags line 955
Sink snippetif (rule->flags & FWDB_FLAG_AUTO_BW)
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->flags from out-of-bounds firmware offset
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= firmware_size before dereferencing rule.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #31 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->flags line 956
Sink snippetrrule->flags |= NL80211_RRF_AUTO_BW;
Possibly guardedno
Dismissed: rrule is locally allocated memory. False positive.

Finding #32 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->dfs_cac_ms line 958
Sink snippetrrule->dfs_cac_ms = 0;
Possibly guardedno
Dismissed: rrule->dfs_cac_ms is a write to locally allocated regdom->reg_rules[i]. False positive.

Finding #33 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->len line 961
Sink snippetif (rule->len >= offsetofend(struct fwdb_rule, cac_timeout))
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->len from out-of-bounds firmware offset
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= firmware_size before accessing rule->len. The check 'rule->len >= offsetofend(...)' assumes rule is already safely accessible.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #34 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Pointer derefrrule->dfs_cac_ms line 962
Sink snippetrrule->dfs_cac_ms =
Possibly guardedno
Dismissed: rrule->dfs_cac_ms is a write to locally allocated memory. False positive.

Finding #35 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->cac_timeout line 963
Sink snippet1000 * be16_to_cpu(rule->cac_timeout);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->cac_timeout if rule points outside firmware buffer
Fix: First validate rule_ptr + rule->len <= firmware_size and rule_ptr + sizeof(struct fwdb_rule) <= firmware_size. The existing check on rule->len is insufficient because rule itself may be OOB.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #36 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Pointer derefrule->len line 964
Sink snippetif (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr))
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds reading rule->len from out-of-bounds firmware offset
Fix: Validate rule_ptr + sizeof(struct fwdb_rule) <= firmware_size before accessing any rule fields including rule->len.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #37 — Category E — cross-function via set_wmm_rule() — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 965 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 853
Sink snippetecw2cw((wmm->client[i].ecw & 0xf0) >> 4);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule reading wmm fields from out-of-bounds firmware offset
Fix: Validate wmm_ptr (= be16_to_cpu(rule->wmm_ptr) << 2) + sizeof(struct fwdb_wmm_rule) <= firmware_size in set_wmm_rule before dereferencing wmm. The valid_wmm() call should include bounds checking against the firmware buffer size.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #38 — Category E — cross-function via set_wmm_rule() — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 965 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 854
Sink snippetwmm_rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule reading wmm->client[i].ecw
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= firmware_size before accessing wmm fields.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #39 — Category E — cross-function via set_wmm_rule() — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 965 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 855
Sink snippetwmm_rule->client[i].aifsn = wmm->client[i].aifsn;
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule reading wmm->client[i].aifsn
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= firmware_size before accessing wmm fields.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #40 — Category E — cross-function via set_wmm_rule() — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 965 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 857
Sink snippet1000 * be16_to_cpu(wmm->client[i].cot);
Possibly guardedyes (heuristic)
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule reading wmm->client[i].cot
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= firmware_size before accessing wmm fields.
CVE pattern: Firmware parsing OOB read via unvalidated offset

Finding #41 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 965 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 858
Sink snippetwmm_rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
Possibly guardedyes (heuristic)
Dismissed: Sink is wmm->ap[i] in set_wmm_rule(). wmm is derived from rule->wmm_ptr, but valid_wmm(wmm) is called at line 844 before any wmm dereference. The flagged sinks at 858-861 are after this validation gate.

Finding #42 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 965 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 859
Sink snippetwmm_rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
Possibly guardedyes (heuristic)
Dismissed: Same as #1 — wmm validated by valid_wmm() before line 859 access.

Finding #43 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 965 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 860
Sink snippetwmm_rule->ap[i].aifsn = wmm->ap[i].aifsn;
Possibly guardedyes (heuristic)
Dismissed: Same as #1 — wmm validated by valid_wmm() before line 860 access.

Finding #44 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 935
Taint snippetunsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
Tainted varrule
Call siteline 965 — passes rule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrule-> line 861
Sink snippetwmm_rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot);
Possibly guardedyes (heuristic)
Dismissed: Same as #1 — wmm validated by valid_wmm() before line 861 access.

Finding #45 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Call siteline 965 — passes rrule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrrule-> line 853
Sink snippetecw2cw((wmm->client[i].ecw & 0xf0) >> 4);
Possibly guardedno
Dismissed: rrule points into locally-allocated regdom (kzalloc_flex sized to n_rules). i is bounded by n_reg_rules==n_rules, so access is within allocation. Taint propagation through index into local allocation is a false positive.

Finding #46 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Call siteline 965 — passes rrule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrrule-> line 854
Sink snippetwmm_rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
Possibly guardedno
Dismissed: Same as #5 — rrule is a pointer into locally-allocated regdom, not a server-controlled pointer.

Finding #47 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Call siteline 965 — passes rrule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrrule-> line 855
Sink snippetwmm_rule->client[i].aifsn = wmm->client[i].aifsn;
Possibly guardedno
Dismissed: Same as #5.

Finding #48 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Call siteline 965 — passes rrule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrrule-> line 857
Sink snippet1000 * be16_to_cpu(wmm->client[i].cot);
Possibly guardedno
Dismissed: Same as #5.

Finding #49 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Call siteline 965 — passes rrule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrrule-> line 858
Sink snippetwmm_rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
Possibly guardedno
Dismissed: Same as #5.

Finding #50 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Call siteline 965 — passes rrule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrrule-> line 859
Sink snippetwmm_rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
Possibly guardedno
Dismissed: Same as #5.

Finding #51 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Call siteline 965 — passes rrule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrrule-> line 860
Sink snippetwmm_rule->ap[i].aifsn = wmm->ap[i].aifsn;
Possibly guardedno
Dismissed: Same as #5.

Finding #52 — Category E — cross-function via set_wmm_rule() — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 919
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varrrule
Call siteline 965 — passes rrule to set_wmm_rule()
Call snippetset_wmm_rule(db, country, rule, rrule);
Pointer derefrrule-> line 861
Sink snippetwmm_rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot);
Possibly guardedno
Dismissed: Same as #5.

set_wmm_rule() — net/wireless/reg.c BUG confidence=medium

The wmm_ptr offset derived from the firmware regulatory database is never validated against the total database buffer size before being used to form a pointer. valid_wmm() validates the semantic values inside the struct (cw_min < cw_max, aifsn >= 1) but does NOT verify that wmm_ptr + sizeof(struct fwdb_wmm_rule) <= db_end. If a malformed/malicious regulatory database provides an out-of-range wmm_ptr, both valid_wmm() and the subsequent loop would read out-of-bounds memory. valid_wmm() does access the same fields (covering client[] and ap[] arrays via the ac[] cast), so it would also fault first — but it doesn't constitute a bounds check.

Finding #1 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 841
Taint snippetwmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
Tainted varwmm
Pointer derefwmm->client line 853
Sink snippetecw2cw((wmm->client[i].ecw & 0xf0) >> 4);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds or general protection fault in valid_wmm/set_wmm_rule when processing a malformed regulatory database with out-of-range wmm_ptr
Fix: Before forming the wmm pointer, validate: wmm_ptr + sizeof(struct fwdb_wmm_rule) <= db_size (where db_size is the total size of the loaded regulatory database blob). Add this check before the valid_wmm() call.
CVE pattern: Firmware blob offset OOB read via unchecked offset arithmetic

Finding #2 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 841
Taint snippetwmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
Tainted varwmm
Pointer derefwmm->client line 854
Sink snippetwmm_rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule when processing malformed regulatory database
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= db_size before dereferencing wmm.
CVE pattern: Firmware blob offset OOB read via unchecked offset arithmetic

Finding #3 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 841
Taint snippetwmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
Tainted varwmm
Pointer derefwmm->client line 855
Sink snippetwmm_rule->client[i].aifsn = wmm->client[i].aifsn;
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule when processing malformed regulatory database
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= db_size before dereferencing wmm.
CVE pattern: Firmware blob offset OOB read via unchecked offset arithmetic

Finding #4 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 841
Taint snippetwmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
Tainted varwmm
Pointer derefwmm->client line 857
Sink snippet1000 * be16_to_cpu(wmm->client[i].cot);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule when processing malformed regulatory database
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= db_size before dereferencing wmm.
CVE pattern: Firmware blob offset OOB read via unchecked offset arithmetic

Finding #5 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 841
Taint snippetwmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
Tainted varwmm
Pointer derefwmm->ap line 858
Sink snippetwmm_rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule when processing malformed regulatory database
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= db_size before dereferencing wmm.
CVE pattern: Firmware blob offset OOB read via unchecked offset arithmetic

Finding #6 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 841
Taint snippetwmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
Tainted varwmm
Pointer derefwmm->ap line 859
Sink snippetwmm_rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule when processing malformed regulatory database
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= db_size before dereferencing wmm.
CVE pattern: Firmware blob offset OOB read via unchecked offset arithmetic

Finding #7 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 841
Taint snippetwmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
Tainted varwmm
Pointer derefwmm->ap line 860
Sink snippetwmm_rule->ap[i].aifsn = wmm->ap[i].aifsn;
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule when processing malformed regulatory database
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= db_size before dereferencing wmm.
CVE pattern: Firmware blob offset OOB read via unchecked offset arithmetic

Finding #8 — Category E — BUG oob_read

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 841
Taint snippetwmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
Tainted varwmm
Pointer derefwmm->ap line 861
Sink snippetwmm_rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot);
Possibly guardedno
Server-suppliedyes
Check presentyes
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in set_wmm_rule when processing malformed regulatory database
Fix: Validate wmm_ptr + sizeof(struct fwdb_wmm_rule) <= db_size before dereferencing wmm.
CVE pattern: Firmware blob offset OOB read via unchecked offset arithmetic

valid_country() — net/wireless/reg.c FP confidence=high

valid_country() performs careful sequential validation: line 706 checks that coll+offsetofend(n_rules) fits in the buffer before reading coll->len or coll->n_rules; line 710-711 then checks the full extent including the rules array; line 715 validates coll->len is large enough. All struct field accesses on coll occur after these guards. The loop at line 720 is bounded by the check at line 711 (coll->n_rules*2 bytes of rules_ptr array verified in-bounds). valid_rule() is itself the validator for rule_ptr — its internal accesses are validation logic, not vulnerable sinks.

Finding #1 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 700
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->len line 710
Sink snippetif ((u8 *)coll + ALIGN(coll->len, 2) +
Possibly guardedyes (heuristic)
Dismissed: Line 706 checks (u8*)coll + offsetofend(typeof(*coll), n_rules) > data + size before any field access. This covers coll->len at line 710. Cannot construct counterexample: any ptr that would place coll->len outside the buffer would fail line 706.

Finding #2 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 700
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->n_rules line 711
Sink snippet(coll->n_rules * 2) > data + size)
Possibly guardedyes (heuristic)
Dismissed: Line 706 checks offsetofend(typeof(*coll), n_rules) which includes n_rules in bounds verification. Cannot construct counterexample that passes line 706 but allows OOB read of n_rules.

Finding #3 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 700
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->len line 715
Sink snippetif (coll->len < offsetofend(struct fwdb_collection, dfs_region))
Possibly guardedyes (heuristic)
Dismissed: By line 715, both prior checks at 706 and 710-711 have passed, ensuring coll->len is safely readable. This access is protected.

Finding #4 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 700
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->len line 718
Sink snippetrules_ptr = (void *)((u8 *)coll + ALIGN(coll->len, 2));
Possibly guardedyes (heuristic)
Dismissed: Line 718 access to coll->len is after all three guards (706, 710-711, 715) have passed. Fully protected.

Finding #5 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcebe16_to_cpu() line 700
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Loopfor_loop line 720
Sink snippetfor (i = 0; i < coll->n_rules; i++) {
Possibly guardedyes (heuristic)
Dismissed: Line 710-711 verifies coll->n_rules*2 bytes fit in the buffer before the loop. The loop iterates exactly coll->n_rules times over rules_ptr[i], which was validated to fit. Each iteration calls valid_rule() which validates the rule_ptr value independently.

Finding #6 — Category E — false positive

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 700
Taint snippetunsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
Tainted varcoll
Pointer derefcoll->n_rules line 720
Sink snippetfor (i = 0; i < coll->n_rules; i++) {
Possibly guardedyes (heuristic)
Dismissed: coll->n_rules at line 720 is safe to read; line 706 ensures offsetofend(n_rules) bytes are in bounds. Same argument as finding #2.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 721
Taint snippetu16 rule_ptr = be16_to_cpu(rules_ptr[i]);
Tainted varrule_ptr
Call siteline 723 — passes rule_ptr to valid_rule()
Call snippetif (!valid_rule(data, size, rule_ptr))
Pointer derefrule_ptr-> line 676
Sink snippetif ((u8 *)rule + sizeof(rule->len) > data + size)
Possibly guardedno
Dismissed: valid_rule() IS the validation function for rule_ptr. The access at line 676 inside valid_rule() is the validation check itself, not a vulnerable sink. False positive by definition — the function exists to validate its argument.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 721
Taint snippetu16 rule_ptr = be16_to_cpu(rules_ptr[i]);
Tainted varrule_ptr
Call siteline 723 — passes rule_ptr to valid_rule()
Call snippetif (!valid_rule(data, size, rule_ptr))
Pointer derefrule_ptr-> line 680
Sink snippetif (rule->len < offsetofend(struct fwdb_rule, max_bw))
Possibly guardedyes (heuristic)
Dismissed: Access at line 680 in valid_rule() is guarded by the check at line 676. valid_rule() validates its argument before this access. False positive — validation function internals.

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 721
Taint snippetu16 rule_ptr = be16_to_cpu(rules_ptr[i]);
Tainted varrule_ptr
Call siteline 723 — passes rule_ptr to valid_rule()
Call snippetif (!valid_rule(data, size, rule_ptr))
Pointer derefrule_ptr-> line 682
Sink snippetif (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) {
Possibly guardedyes (heuristic)
Dismissed: Access at line 682 is guarded by lines 676 and 680. This is internal validation logic in valid_rule().

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

CategoryCat E — tainted pointer dereference (->field access beyond packet bounds)
Taint sourcebe16_to_cpu() line 721
Taint snippetu16 rule_ptr = be16_to_cpu(rules_ptr[i]);
Tainted varrule_ptr
Call siteline 723 — passes rule_ptr to valid_rule()
Call snippetif (!valid_rule(data, size, rule_ptr))
Pointer derefrule_ptr-> line 683
Sink snippetu32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
Possibly guardedyes (heuristic)
Dismissed: Access at line 683 (rule->wmm_ptr) is inside the branch guarded by rule->len >= offsetofend(struct fwdb_rule, wmm_ptr) at line 682, which itself is after the sizeof(rule->len) check at line 676. Fully protected validation logic.

cfg80211_parse_ml_elem_sta_data() — net/wireless/scan.c FP confidence=high

The function has solid validation discipline: ieee80211_mle_type_ok() validates the ML element, cfg80211_defrag_mle() validates and bounds-checks all sta_prof entries, ieee80211_mle_basic_sta_prof_size_ok() checks each profile before use, and explicit size guards protect buffer writes. All three findings are false positives: #1 because link_id uses a 4-bit mask fitting u8; #2 because cfg80211_rnr_info_for_mld_ap returns u8 directly; #3 because reporter_rnr->datalen is u8 (max 255) and protected by an explicit overflow guard.

Finding #1 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 3044
Taint snippetlink_id = u16_get_bits(control,
Tainted varlink_id
Truncationline 3044: 16 → 8-bit u8
Sink snippetlink_id = u16_get_bits(control,
Possibly guardedno
Dismissed: IEEE80211_MLE_STA_CONTROL_LINK_ID is a 4-bit mask (0x000F). u16_get_bits() applies this mask before assignment to u8 link_id, so the result is always 0-15, well within u8 range. No counterexample can produce a value exceeding u8 max given the mask. The truncation is safe by construction.

Finding #2 — Category H — false positive

CategoryCat H — server value → narrow integer type (silent truncation)
Taint sourcele16_to_cpu() line 3075
Taint snippetuse_for = cfg80211_rnr_info_for_mld_ap(tx_data->ie,
Tainted varuse_for
Truncationline 3075: 16 → 8-bit u8
Sink snippetuse_for = cfg80211_rnr_info_for_mld_ap(tx_data->ie,
Possibly guardedno
Dismissed: cfg80211_rnr_info_for_mld_ap() is declared as returning u8 (line 2830), so assigning its return to u8 use_for involves no truncation at all. The scanner's claim that this is a 16-bit-to-8-bit truncation is incorrect. The taint chain through link_id is also broken since link_id is already bounded to 4 bits. False positive.

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

CategoryCat B — integer overflow: sizeof(struct element) + reporter_rnr->datalen
Taint sourcele16_to_cpu() line 2978
Taint snippetcontrol = le16_to_cpu(ml_elem->control);
Tainted varreporter_rnr
Overflow exprsizeof(struct element) + reporter_rnr->datalen
Safe fixkmalloc_array() or check_mul_overflow()
Sinkmemcpy() line 3179 (arg 2, role=size_mul_overflow)
Sink snippetmemcpy(new_ie + data.ielen, reporter_rnr,
Possibly guardedyes (heuristic)
Dismissed: reporter_rnr is kernel-generated by cfg80211_gen_reporter_rnr(), not a direct server-supplied buffer. reporter_rnr->datalen is of type u8 (struct element field), bounded to 0-255. sizeof(struct element)+datalen is at most 257, no integer overflow possible. The explicit guard at lines 3175-3177 checks that data.ielen + sizeof(struct element) + reporter_rnr->datalen <= IEEE80211_MAX_DATA_LEN before the memcpy. No counterexample exists that bypasses this guard while causing OOB.

cfg80211_get_p2p_attr() — net/wireless/util.c FP confidence=high

The function is careful about both source and destination bounds. For source buffer safety, copy is computed as min(attr_len, iedatalen), where iedatalen is the remaining validated IE data length — so the read never goes past the input buffer. For destination buffer safety, the memcpy size argument is min(bufsize, copy), where bufsize tracks remaining output space and is decremented after each copy — so the write never exceeds the output buffer. The taint from get_unaligned_le16() is fully contained by these two independent guards.

Finding #1 — Category B — false positive

CategoryCat B — server value → size/alloc argument
Taint sourceget_unaligned_le16() line 2004
Taint snippetattr_len = get_unaligned_le16(iedata + 1);
Tainted varcopy
Sinkmemcpy() line 2013 (arg 2, role=size)
Sink snippetmemcpy(out, iedata, min(bufsize, copy));
Possibly guardedno
Dismissed: Two independent bounds checks protect the memcpy: (a) copy = min_t(unsigned int, attr_len, iedatalen) at line 2008 caps the read against remaining IE data, preventing OOB read of the source buffer; (b) min(bufsize, copy) at line 2013 caps the write against remaining destination buffer space, preventing OOB write. A concrete counterexample — e.g., attr_len=0xFFFF, iedatalen=50, bufsize=10 — results in copy=50 and memcpy size=10, both safe. No counterexample that bypasses both guards simultaneously can be constructed.

ioctl_private_iw_point() — net/wireless/wext-priv.c FP confidence=high

extra_size is computed by get_priv_descr_and_size() from kernel-internal device/command descriptors, not from user-supplied data. The kzalloc() allocation uses the same extra_size, so copy_from_user uses it against a buffer of exactly that size. For copy_to_user, adjust_priv_size() may modify extra_size but is constrained by kernel descriptor masks and should not exceed the original allocation. Both findings are false positives.

Finding #1 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_from_user() line 160
Taint snippetif (copy_from_user(extra, iwp->pointer, extra_size)) {
Tainted varextra_size
Unvalidated sizecopy_from_user() arg 2 line 160 — size extra_size
Sink snippetif (copy_from_user(extra, iwp->pointer, extra_size)) {
Possibly guardedno
Dismissed: extra_size comes from get_priv_descr_and_size() — a kernel-internal computation based on device command descriptors, not user input. The buffer extra is allocated with kzalloc(extra_size), so copy_from_user(..., extra_size) stays within bounds. No counterexample possible since extra_size is not user-controlled.

Finding #2 — Category G2 — false positive

CategoryCat G2 — unvalidated size argument to copy_from/to_user
Taint sourcecopy_to_user() line 177
Taint snippetif (copy_to_user(iwp->pointer, extra, extra_size))
Tainted varextra_size
Unvalidated sizecopy_to_user() arg 2 line 177 — size extra_size
Sink snippetif (copy_to_user(iwp->pointer, extra, extra_size))
Possibly guardedno
Dismissed: After adjust_priv_size(), extra_size is based on descr->get_args (kernel constant mask) and iwp->length (set by kernel handler post-execution). The adjusted size is structurally bounded by the descriptor's IW_PRIV_SIZE_MASK and should not exceed the originally allocated buffer size. No user-controlled path can inflate extra_size beyond the kzalloc'd buffer.

xfrm_input() — net/xfrm/xfrm_input.c FP confidence=high

The function has sound validation discipline. The taint chain reported by the scanner is incorrect: 'mark' (derived from be32_to_cpu at line 565) is not the same as 'x->props.family' used at line 756. 'x' is an xfrm_state retrieved from the kernel's own internal state database via xfrm_input_state_lookup(), not from the incoming network packet. Furthermore, xfrm_state_afinfo_get_rcu() itself validates its 'family' argument against NPROTO before using it as an array subscript, and the caller checks for NULL return.

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

CategoryCat C — server value → array subscript
Taint sourcebe32_to_cpu() line 565
Taint snippetmark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6->parms.i_key);
Tainted varx
Call siteline 756 — passes x to xfrm_state_afinfo_get_rcu()
Call snippetafinfo = xfrm_state_afinfo_get_rcu(x->props.family);
Subscript (in callee)[] line 3127
Sink snippetreturn rcu_dereference(xfrm_state_afinfo[family]);
Possibly guardedyes (heuristic)
Dismissed: The scanner incorrectly propagates taint from 'mark' (set via be32_to_cpu at line 565) to 'x' (returned by xfrm_input_state_lookup). The value x->props.family used at line 756 originates from a kernel-internal xfrm_state struct, not from the network packet. Additionally, xfrm_state_afinfo_get_rcu() validates family >= NPROTO before indexing, and the caller handles the NULL return with 'if (likely(afinfo))'. No counterexample can be constructed: the taint chain is broken at the state lookup boundary.

xfrmi4_err() — net/xfrm/xfrm_interface_core.c FP confidence=high

The static analyzer over-approximates taint by treating the return value of xfrm_state_lookup() as tainted because its argument (spi) was derived from network data. However, xfrm_state_lookup() uses spi only as a lookup key into the kernel's internal xfrm state table; the returned xfrm_state struct and its fields (including if_id used in xfrmi_hash()) are kernel-controlled, not populated from the incoming packet. The NULL check at line 627-628 ensures x is valid before use.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 608
Taint snippetspi = htonl(ntohs(ipch->cpi));
Tainted varx
Call siteline 630 — passes x to xfrmi_lookup()
Call snippetxi = xfrmi_lookup(net, x);
Subscript (in callee)[] line 159
Sink snippetfor_each_xfrmi_rcu(xfrmn->xfrmi[xfrmi_hash(x->if_id)], xi) {
Possibly guardedno
Dismissed: The taint flows from network-supplied spi into xfrm_state_lookup() as a lookup key, but the returned xfrm_state *x is a kernel-internal object whose fields are set by kernel configuration (xfrm policy/state management), not by the incoming packet. The field x->if_id used as xfrmi_hash() argument is kernel-controlled. xfrm_state_lookup() returns NULL (checked at line 627) if no matching state exists, so any non-NULL x is a valid kernel struct. The scanner is performing taint propagation across a lookup boundary incorrectly — this is a well-known false positive pattern where lookup-key taint does not propagate to lookup result fields. No counterexample is possible since x->if_id cannot be influenced by the attacker.

xfrmi6_err() — net/xfrm/xfrm_interface_core.c FP confidence=high

The taint chain is broken at xfrm_state_lookup(). The network-supplied 'spi' value is used as a hash table lookup key, not as a direct memory offset. The returned 'x' pointer is a kernel-managed struct xfrm_state object whose 'if_id' field is set by local kernel configuration (not derived from packet data). The xfrmi_hash(x->if_id) array subscript uses kernel-controlled data, not server-supplied data. Additionally, the NULL check on x at line 681-682 properly guards against lookup failure.

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

CategoryCat C — server value → array subscript
Taint sourcentohs() line 669
Taint snippetspi = htonl(ntohs(ipch->cpi));
Tainted varx
Call siteline 684 — passes x to xfrmi_lookup()
Call snippetxi = xfrmi_lookup(net, x);
Subscript (in callee)[] line 159
Sink snippetfor_each_xfrmi_rcu(xfrmn->xfrmi[xfrmi_hash(x->if_id)], xi) {
Possibly guardedno
Dismissed: The scanner incorrectly propagates taint through xfrm_state_lookup(). While 'spi' is network-supplied and used as a lookup key, the returned 'struct xfrm_state *x' is a kernel-internal object stored in the xfrm state hash table. Its 'if_id' field is set at state creation time by local configuration, not derived from packet content. xfrmi_hash() produces a bounded index into xfrmn->xfrmi[]. No counterexample exists because x->if_id is not attacker-controlled. The NULL check at line 681 guards against failed lookups. This is a false positive due to taint over-approximation across the hash table lookup boundary.

__input_process_payload() — net/xfrm/xfrm_iptfs.c FP confidence=high

The function properly validates IPv4/IPv6 header fields before use (checking remaining bytes, validating iplen >= iphlen, etc.). The taint chain reported here is a scanner artifact: it tracks skb as tainted because it was allocated with iplen derived from be16_to_cpu(payload_len), then flags sp->xvec[sp->len++] inside xfrm_input() as an array subscript vulnerability. However, the array index sp->len is a kernel-internal security path depth counter, explicitly bounds-checked against XFRM_MAX_DEPTH before the array access — it is entirely independent of the network-supplied IPv6 payload_len field.

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

CategoryCat C — server value → array subscript
Taint sourcebe16_to_cpu() line 1019
Taint snippetiplen = be16_to_cpu(((struct ipv6hdr *)hbytes)->payload_len);
Tainted varskb
Call siteline 1191 — passes skb to xfrm_input()
Call snippetif (xfrm_input(skb, 0, 0, -2))
Subscript (in callee)[] line 612
Sink snippetsp->xvec[sp->len++] = x;
Possibly guardedyes (heuristic)
Dismissed: The scanner propagates taint from be16_to_cpu(payload_len) → iplen → skb (pointer allocation) → xfrm_input(skb) → sp->xvec[sp->len++]. The array subscript sp->len is the security path depth, not derived from iplen. It is protected by the explicit check 'if (sp->len == XFRM_MAX_DEPTH) goto drop' at line 587 of xfrm_input(). No counterexample exists: sp->len cannot exceed XFRM_MAX_DEPTH regardless of what payload_len contains. This is a taint-tracking false positive caused by treating the skb pointer as uniformly tainted and then flagging unrelated array accesses inside xfrm_input().

iptfs_input_ordered() — net/xfrm/xfrm_iptfs.c FP confidence=high

The function carefully validates the IPTFS header from network data, uses skb_copy_seq_read() which enforces skb bounds internally, and the 'data' value returned from iptfs_reassem_cont() is validated per its postcondition. The loop in __input_process_payload() uses 'while (data < tail)' where tail=skb->len, making it a naturally bounded traversal — data controls when the loop runs, not an array index without bounds.

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

CategoryCat F — server value → loop iteration count
Taint sourcentohs() line 1273
Taint snippetblkoff = ntohs(ipth->block_offset);
Tainted vardata
Call siteline 1288 — passes data to __input_process_payload()
Call snippetconsumed = __input_process_payload(x, data, &skbseq, &sublist);
Loopwhile_loop line 974
Sink snippetwhile (data < tail) {
Possibly guardedno
Dismissed: The tainted 'data' value is used as the starting offset in a while loop 'while (data < tail)' where tail=skb->len. This is a standard bounded traversal: if data >= skb->len the loop simply does not execute. Within the loop, remaining=tail-data is always positive, and skb_copy_seq_read() validates offsets against skb bounds internally. The iptfs_reassem_cont() validator postcondition establishes that the returned data offset is valid within the skb. No counterexample exists that would allow data to cause OOB — the loop condition itself is the bound. False positive.

xfrm_replay_advance_bmp() — net/xfrm/xfrm_replay.c MIXED confidence=medium

Finding #1 (loop) is a false positive because diff < replay_window is checked before the loop and per-iteration modulo keeps bitnr in bounds. Finding #2 is a potential real bug: in the else branch (seq <= replay_esn->seq), diff has no upper bound check; if pos < diff and (diff - pos) > replay_window, the expression replay_window - (diff - pos) underflows as u32, yielding a huge bitnr and nr values, causing OOB write to bmp[].

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 262
Taint snippetu32 seq = ntohl(net_seq);
Tainted vardiff
Loopfor_loop line 274
Sink snippetfor (i = 1; i < diff; i++) {
Possibly guardedyes (heuristic)
Dismissed: The guard at line 273 (diff < replay_esn->replay_window) ensures the loop runs at most replay_window-1 times. Per-iteration modulo at line 275 keeps bitnr in [0, replay_window-1], so nr = bitnr>>5 stays within bmp[] bounds. No counterexample possible: any diff >= replay_window takes the else branch entirely, skipping the loop.

Finding #2 — Category C — BUG oob_write

CategoryCat C — server value → array subscript
Taint sourcentohl() line 262
Taint snippetu32 seq = ntohl(net_seq);
Tainted varnr
Subscript[] line 299
Sink snippetreplay_esn->bmp[nr] |= (1U << bitnr);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in xfrm_replay_advance_bmp; kernel crash or heap corruption writing to replay_esn->bmp[nr] where nr is derived from underflowed u32 arithmetic
Fix: In the else branch (line 291-294), add a bounds check on diff: if diff > replay_window, the sequence number is outside the window and should be silently dropped or handled — e.g., 'if (diff >= replay_esn->replay_window) return;' before computing bitnr. Also verify the expression replay_window - (diff - pos) cannot underflow by checking diff - pos <= replay_window.
CVE pattern: Integer underflow leading to out-of-bounds array write in replay window bitmap

xfrm_replay_advance_esn() — net/xfrm/xfrm_replay.c MIXED confidence=high

Finding #1 is a false positive because the loop body uses modulo arithmetic that bounds array indices within the valid bmp range. Finding #2 is a real bug in path 3 (line 598): when pos < diff and diff > replay_window, an unsigned integer underflow occurs producing an out-of-bounds bmp index.

Finding #1 — Category F — false positive

CategoryCat F — server value → loop iteration count
Taint sourcentohl() line 563
Taint snippetseq = ntohl(net_seq);
Tainted vardiff
Loopfor_loop line 575
Sink snippetfor (i = 1; i < diff; i++) {
Possibly guardedyes (heuristic)
Dismissed: The loop only executes when diff < replay_esn->replay_window (line 574). Inside the loop, bitnr is computed as (pos+i) % replay_esn->replay_window, which constrains bitnr to [0, replay_window-1] and thus nr = bitnr>>5 to [0, (replay_window-1)>>5]. No counterexample possible — modulo bounds are tight.

Finding #2 — Category C — BUG oob_write

CategoryCat C — server value → array subscript
Taint sourcentohl() line 563
Taint snippetseq = ntohl(net_seq);
Tainted varnr
Subscript[] line 605
Sink snippetreplay_esn->bmp[nr] |= (1U << bitnr);
Possibly guardedno
Server-suppliedyes
Check presentno
Check sufficientno
Symptom: BUG: KASAN: slab-out-of-bounds in xfrm_replay_advance_esn; kernel crash or heap corruption via OOB write to replay_esn->bmp[]
Fix: In the else branch of line 595-598, add a check that diff <= replay_esn->replay_window before computing bitnr. If diff > replay_window and pos < diff-replay_window, clamp or handle appropriately. Specifically: if (diff >= replay_esn->replay_window) bitnr = (replay_esn->replay_window - 1); else bitnr = replay_esn->replay_window - (diff - pos); — or restructure to ensure bitnr always uses modulo arithmetic: bitnr = (replay_esn->replay_window + pos - diff % replay_esn->replay_window) % replay_esn->replay_window.
CVE pattern: Integer underflow leading to out-of-bounds array write in replay window bitmap management

xfrm_replay_check_bmp() — net/xfrm/xfrm_replay.c FP confidence=high

The function correctly bounds `bitnr` to [0, replay_window-1] via the guard at line 231 (`diff >= replay_window` → error). Both branches of the pos/diff comparison yield a value strictly less than replay_window, so `nr = bitnr >> 5` is strictly less than ceil(replay_window/32), which is the allocated size of bmp[]. No counterexample can be constructed that passes the guard yet causes OOB.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 219
Taint snippetu32 seq = ntohl(net_seq);
Tainted varnr
Subscript[] line 245
Sink snippetif (replay_esn->bmp[nr] & (1U << bitnr))
Possibly guardedno
Dismissed: The guard `if (diff >= replay_esn->replay_window) goto err` at line 231 ensures diff < replay_window. Combined with pos = (seq-1) % replay_window (so pos < replay_window), both computation branches yield bitnr in [0, replay_window-1]. Therefore nr = bitnr >> 5 is in [0, (replay_window-1)/32], which is within the allocated bmp[] array sized at ceil(replay_window/32) u32 words. No counterexample exists; the scanner flagged tainted arithmetic that is actually properly bounded.

xfrm_replay_check_esn() — net/xfrm/xfrm_replay.c FP confidence=high

The array subscript 'nr' is derived from 'bitnr >> 5', where 'bitnr' is strictly less than replay_window after the guard at line 484 (diff >= replay_esn->replay_window returns error). Since the bmp[] array is allocated with replay_window/32 words, nr is always a valid index. The taint flows through ntohl() but is fully bounded before the array access.

Finding #1 — Category C — false positive

CategoryCat C — server value → array subscript
Taint sourcentohl() line 458
Taint snippetu32 seq = ntohl(net_seq);
Tainted varnr
Subscript[] line 498
Sink snippetif (replay_esn->bmp[nr] & (1U << bitnr))
Possibly guardedno
Dismissed: The guard at line 484 (if diff >= replay_esn->replay_window → goto err) ensures diff < wsize after that point. pos = (seq-1) % wsize so pos < wsize. In both branches: bitnr = (pos-diff)%wsize < wsize (if pos>=diff), or bitnr = wsize-(diff-pos) where 1<=diff-pos<=wsize-1 so 1<=bitnr<=wsize-1 < wsize (else branch). Therefore nr = bitnr>>5 < wsize/32, which is exactly the allocated size of bmp[]. No counterexample can be constructed — the check is tight and sufficient.